Dougal Campbell's geek ramblings

WordPress, web development, and world domination.

Unit testing in PHP with SimpleTest

simpletest-logo

I recently worked on a PHP project which required me to write a suite of unit tests to verify that the code worked as expected. While I’ve done unit testing before, and I knew that it was valuable, I have to admit that I’ve only used it very rarely. I’ve only had a few jobs/projects that required it, and most other projects didn’t want to pay for the extra time.

Of the PHP test suites I saw, I selected SimpleTest, as it appears to still be actively developed. It’s based on JUnit, as are many testing suites. You create groups of tests as classes which inherit from the UnitTestCase class. Each class contains methods, which in turn establish assertions (which are the actual states that you need to test). In each test, you call out to the functions of your own code, and compare the returned value to the value that you expect to get back. You test these with assertion functions like ‘assertEqual’, ‘assertTrue’, ‘assertIsA’, ‘assertIdentical’, etc. You can test equality, data types, boolean true/false, and other states.

As an example, let’s say you were writing a class for manipulating complex numbers. Our class handles complex numbers as tuples, so ’5 – 3i’ is represented by an array [5, -3]. If we were testing our ‘add’ and ‘multiply’ methods, you might write the tests like so:

  1. <?php
  2. require('complexnumbers-class.php');
  3. require('simpletest/autorun.php');
  4.  
  5. class TestComplex extends UnitTestCase {
  6.   var $complex;
  7.  
  8.   function __construct() {
  9.     $this->complex = new Complex();
  10.     parent::__construct('Complex Number Tests');
  11.   }
  12.  
  13.   function testComplexAdd() {
  14.     $x = array(2, 5); // 2 + 5i
  15.     $y = array(1,-3); // 1 – 3i
  16.     $z = $this->complex->add($x, $y); // should return 3 + 2i
  17.  
  18.     $this->assertIdentical( $z, array(3, 2) );
  19.   }
  20.  
  21.   function test ComplexMultiply() {
  22.     $x = array(2, 5);
  23.     $y = array(1, -3);
  24.     $z = $this->complex->mul($x, $y); // should return 17 – 1i
  25.  
  26.     $this->assertIdentical( $z, array(17, -1) );
  27.   }
  28. }
  29. ?>

When you run the tests, you get a report back, and if any of the tests fail, it tells you which ones. Then you go back and adjust your code, and re-test until all tests succeed.

The SimpleTest web site espouses Test Driven Development (TDD), where you write your tests before you develop your application, then you keep developing your code until all your tests pass. In my case, I had already written my code. And while I tend to break my code down into many ‘blackbox’ functions, and I try to minimize global variables, I ended up refactoring my code a good bit before I was done.

A lot of the code I write is procedural, as opposed to object oriented (or functional, but that’s a whole other animal). It’s really just a bad habit of mine, because I learned to program before most people had ever heard of OOP. It’s not that writing procedural code is inherently bad, but it is quick-and-dirty, and I do find that organizing things into a class encourages me to think harder (and better) about how things should fit together.

While developing my tests, I ended up converting my procedural code into a class. SimpleTest can test against any set of functions, not just classes, but I quickly decided that turning my function library into a class would be better, so that I could get rid of the need for global variables. This particular code needs to read in an external configuration file, and I had hard-coded the filename and location. To properly test all the nooks and crannies of my code, I had to refactor the code so that I could reset the configuration file. This was an improvement over my original approach. Unit testing also turned up a couple of bugs in some functionality that I hadn’t had a chance to test by other means.

All in all, I’d have to say that unit testing my code was a positive experience. I think I’m going to try the TDD approach next time I start a personal project, and see how it affects my development. I’ll have to change how I look at things a little bit, but I think it will probably be worth the effort.

Do you create unit tests, or do you just wing it? Do you develop first, then create tests, or do you use the TDD ‘test first’ approach?

About Dougal Campbell

Dougal is a web developer, and a "Developer Emeritus" for the WordPress platform. When he's not coding PHP, Perl, CSS, JavaScript, or whatnot, he spends time with his wife, three children, a dog, and a cat in their Atlanta area home.
This entry was posted in Development and tagged , , , , , , , , , , . Bookmark the permalink.

2 Responses to Unit testing in PHP with SimpleTest

  1. Marcus Baker says:

    Hi…

    “Do you develop first, then create tests, or do you use the TDD ‘test first’ approach?”

    I tend to write test first or test nearly first. I also use web based acceptance tests as the project spec for smaller projects, so that’s test a week ahead :).

    yours, Marcus

  2. This is a useful topic discussed here and lots of people will find easy way to get those informative posts written by you, Thanks a lot for the effort.

Leave a Reply

%d bloggers like this: