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?

Stumble It!
Unit testing in PHP with SimpleTest

Related posts:

  1. WordPress iPhone App beta testing
    " Do you use WordPress? Do you have an iPhone? Or do you just like beta testing cool apps? You could help beta-test the upcoming..."
  2. Challenges
    " Writing perl unit tests which need to simulate a web browser with cookie support connecting to a server from multiple network interfaces is challenging...."
  3. A PHP Question
    " Okay, here’s a question for some of you PHP OOP gurus out there: How can you use the preg_replace_callback() function from inside of a..."
  4. Cake PHP Framework
    " If you’re like me, you’ve been hearing “Ruby this” and “Rails that” everywhere you go. But I don’t have time right now to be..."
  5. Post Meta
    " Spent some lunch hours this week working on “post meta” hacks for WordPress. This will allow users to add arbitrary extra fields to their..."
This entry was posted in Development and tagged , , , , , , , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Comments

  1. Marcus Baker lastcraft.com
    Posted July 28, 2009 at 8:04 pm | Permalink

    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. Jayadev Designer finsofts.com
    Posted September 28, 2009 at 5:25 am | Permalink

    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.

Post a Comment

Your email is never published nor shared.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Subscribe without commenting

  • Subscribe

  • Follow Me

    Twitter  Facebook  Flickr  Last.fm  LinkedIn  StumbleUpon  Technorati  Delicious  
  • Referrals

    Sign up for Text Link Ads and earn money from your blog.
  • Lifestream