PHPUnit Mastery

As we have mentioned previously, unit testing is very important at Genius.com – more than two-thirds of our lines of code are unit tests providing 72% coverage over our code base. These unit tests are supremely useful both when changing existing code and when writing new code; we even make use of Extreme Programming’s practice of test-driven development when the situation calls for it.

Running Specific Tests

When working on a class for which there are a lot of tests, or slow tests, it is often useful to only run the tests for functions that you are currently working on, allowing you to quickly get feedback on changes you make.  At Genius, we are careful about the way tests are named — test<MethodName>_<DetailsAboutTest>() — so using phpunit’s --filter option to run only tests for a specific method is easy.  If I’m working on the query() method of the Connection class, I only run the pertinent tests while working:

~/trunk/test/unit$ phpunit --filter testQuery_ Connection

Of course, when I’m done with a task, I run the entire class’ tests — and probably our entire test suite — to make sure I haven’t accidentally broken anything.

Generating Code Coverage Reports

Our nightly builds are generated by CruiseControl which makes very useful coverage reports that provide great insight into how thorough tests workout your code.  The downside to a report for the entire test suite is that functions can be tested incidentally — that is, a test may exercise a codepath outside of the class that it is testing directly. This is fine, except the most thorough tests are those that explore codepaths in controlled isolation. That is, the tests for the specific method and containing class cover all of the code therein. Luckily, PHPUnit provides an easy method for generating isolated coverage information. By combining the aforementioned --filter option with --coverage-html <dir>, we can generate a coverage report for all tests covering a specific method (e.g. the query() method mentioned above) to help ensure that the tests are hitting all code-paths.

Ensuring Functional Coverage

As any experienced unit tester will tell you, the success of your unit tests can not be measured purely by the percent of code covered by tests. Actually thinking about what a class does, and ensuring that you test all of that functionality should be the goal of unit testing with high code-coverage percentages being the result. The --testdox output mode has PHPUnit show each test’s name with spaces to break apart CamelCase words, creating a ledgible list of the tests that are performed.  As stated above, we are particular about the way we name tests; a test function’s name includes the name of the tested method and the functionality of the method covered in the particular test.  With these descriptive names, the --testdox output is very useful:

lib_SfUpload
 [x] Process event_ is successful with task event
 [x] Get event org_ returns contacts org
 [x] Get event org_ with non sf org throws exception
 [x] Get org sf admin_ returns org sf admin
 [x] Get org sf admin_ org without sf admin throws exception
...

It’s easy to read down this list and understand what the test class is doing. Paired with the code for the class that is being tested, you can be sure that the test methods are exploring all of the functionality that the class provides.

  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • DZone
  • HackerNews
  • LinkedIn
  • Reddit
  • http://ossigeno.sourceforge.net Giorgio Sironi

    I’ll add the –configuration and –bootstrap options that can save you from writing boilerplate inclusion code at the beginning of each test.