Thursday, January 29, 2009

Using PHPUnit's dataProvider for comprehensive failure testing

Writing tests to make sure your application handles failure conditions appropriately is one of the more difficult things to do. It's much easier to write a unit test case to make sure a function or method works when correct parameters are passed. PHPUnit provides some features that will enable you to easily write robust tests to test those failure conditions. Today I'm going to talk about using PHPUnit's dataProvider functionality.

Suppose you had the following static method:

class Example
{

    /**
     * An example method
     *
     * @param   array  $data
     * @return  void
     */
    public static function one($data)
    {

        if (!is_array($data)) {
            throw new Exception('Array expected');
        }

        if (!array_key_exists('one', $data)) {
            throw new Exception('Key (one) is required');
        }

        if (!array_key_exists('two', $data)) {
            throw new Exception('Key (two) is required');
        }

        $data['one'] = true;
        $data['two'] = false;
        return $data;
    }
}

Let's use PHPUnit's dataProvider to test all the failure conditions of the method Example::one(). Data providers must return an array of arrays representing the parameter set of the test method. In this case we are going to have a test method that accepts 3 parameters; a data set, an exception type, and an exception message.

class ExampleTest extends PHPUnit_Framework_TestCase
{
    /**
     * Test failure
     *
     * @test
     * @dataProvider failureDataProvider
     * @return  void
     */
    public function failure($data, $exception, $message)
    {
        $this->setExpectedException($exception, $message);
        Example::one($data);
    }
}

As you will notice, the PHPDoc of the test method defines the data provider method name using the '@dataProvider' tag. Let's define the data provider.

    /**
     * Failure Data Provider
     * @return  array
     */
    public function failureDataProvider()
    {
        return array(
            array('', 'Exception', 'Array expected'),
            array(false, 'Exception', 'Array expected'),
            array('foo', 'Exception', 'Array expected'),
            array(new Example(), 'Exception', 'Array expected'),
            array(array(), 'Exception', 'Key (one) is required'),
            array(array('somekey' => 'somevalue'), 'Exception', 'Key (one) is required'),
            array(array('one' => 'somevalue'), 'Exception', 'Key (two) is required'),
        );
    }

In this data provider we test all the possible failure conditions for the method Example::one(). Using a data provider keeps your tests clear and concise and enables the addition of additional test parameters with ease. All you need to do is simply add another array to test a new value. Let's see the result of our test.

# phpunit --verbose ExampleTest.php
PHPUnit 3.3.9 by Sebastian Bergmann.

ExampleTest
 ExampleTest::failure
 .......

Time: 0 seconds

OK (7 tests, 14 assertions)

The data provider functionality makes it easy to test large combinations of parameters for any method. Read more about the data provider functionality in the PHPUnit documentation.

Monday, January 26, 2009

Coding Efficiency or Maintenance Nightmare: using full descriptive naming in development

As a developer who prides myself in the less popular things such as documentation and standardized code I find it frustrating when I read code that has been "shortened" or "abbreviated" in the name of efficiency. A common theme I am struggling with these days is developers who choose to abbreviate their code for reasons such as "its easier to type" or "it fits better on the screen". As an example, I am frequently seeing the use of a variable name of 'q' instead of 'query' or 'u' instead of 'username'. Don't get me wrong, I am all for efficiencies. But when maintaining this code I find it is much more difficult to understand in order to improve or fix when these abbreviations have been used throughout the code. Imagine a method that finds data in several databases and the variables in scope are 'q', 'u', 'p', 'r', 'd'. Thats a headscratcher if any complexity is involved in the method.

Adding to the frustration is the argument that involves simple editors as a valid reason for this approach. I love 'vi' but for development a good IDE is second to none. Using context assist in eclipse can reduce your overall keystrokes when you need to type out 'username' instead of 'u' and can prevent you from typos. Yes, I see tons of typos in code developed by developers using 'vi'(probably an exception to the rule, but I have my doubts). Using a simple editor is not an excuse.

Is it really too much to ask to type out 'query' instead of 'q'? Descriptive naming in classes, methods, and variables/properties can result in less protracted maintenance over the life of a piece of code. I personally found it difficult when I first decided to be more descriptive in my syntax. However, in a short amount of time you will find it becomes much easier to find appropriate and descriptive names and your code will improve. In the end, you owe it to your fellow developers to do everything in your power to make everyone's life easier through more descriptive syntax.