ASPit - Totally ASP JSit - Totally JavaScript
Search PHPit

Use this textbox to search for articles on PHPit. Seperate keywords with a space.

Advertisements

An introduction to Test Driven Development with PHP

(Page 2 out of 2)

Biter returns right match?

The first thing we want to make sure is that our Biter class will return the right match when we use the bite() method, so let's write a test for that:

function testBiteReturnsAPatternMatch() {
$biter =& new Biter;
        $haystack = 'foobar';
               
        $this->assertEqual(
                        $biter->bite('/foo/', $haystack),
                        'foo',
                        'Biter returns correct match');
}

This test makes sure that the biter returns the correct match. The assertEqual() method is used, which should be fairly self-explanatory. Add the test to our test suite, and run the tests again. It should fail and even return a fatal error, since we haven't implemented the bite() method yet. You should get the following:

Just like we did with our previous test, let's make sure this test passes. The only way we can do this is by implementing the bite() method, and since our test defines how the bite() method should work we only need to develop it, and no longer need to think about how it should. This is another key concept of TDD: the tests define what our code should do.

The following bite() method should make the test pass:

function bite($needle, $haystack) {
        if(preg_match($needle, $haystack, $match)) {
                return $match['0'];
        }
}

Add the bite() method to your Biter class and run the tests again. They should now pass, and produce the following screen:

Let's re-cap what we just did. Instead of creating the bite() method immediately, we first created a test for it, and only then did we implement the bite() method. This is exactly what TDD entails: test first, develop later.

Removing the matched portion

But we aren't completely there yet, because our Biter class has a second requirement: it should remove the matched portion from the original string. Let's write a test for that again:

function testPatternMatchIsRemovedFromHaystack() {
        $biter =& new Biter;
        $haystack = 'foobar';
        $biter->bite('/foo/', $haystack);
        $this->assertEqual($haystack, 'bar', 'Removed matched part [%s]');
}

Again we use the assertEqual() method to assert that two variables are exactly the same, but this time we check if the matched portion has been removed from the haystack.

Run the above test, and it should produce the following:

Now we have to make sure this test passes. It's fairly easy to do so, but suppose we can't figure it out, and to make this test pass, we have to change another test slightly. Seems reasonable right? Wrong!

You should NEVER change other tests to make a certain test easier to pass!

Those other tests might have been created as a result of certain requirements. Your actual script might depend on certain functionality that those other tests test. If you start changing other tests, you lose all advantage of TDD. That's why you should never change other tests to make a certain test pass.

Let's get back to our Biter class. How can we have this test pass? We have to change the haystack that was passed somehow, so it's seems logical to have the haystack passed by reference. Then all we need to do is replace the match we found in the haystack. Our updated bite() method looks like this then:

function bite($needle, &$haystack) {
        if(preg_match($needle, $haystack, $match)) {
                $haystack = str_replace($match['0'], '', $haystack);
                return $match['0'];
        }
}

Put it in your Biter class, and run the tests again. What will you see? All green!

Now that we've satisfied all the requirements for our Biter class we're finished, and we can move on to another class or part of our script, developing it in exactly the same way as we developed the Biter class. And what's even better is that you can regularly run the tests for the Biter class to make sure it still works properly (to prevent from accidentally changing it during development).

Conclusion

In this article I've shown you how Test Driven Development works. We've only created a really simple class, and it was extremely easy to apply TDD, but it's a good introduction.

Be aware though that TDD will require a major shift of focus, and it's hard to get into, because it's a complete different way of programming. The best advice I can give is keep trying to use TDD, and eventually you'll get a hang of it. Once you do you'll never have it any other way.

If you want to know more about the example project in this article, or want to follow another example, have a look at the original thread on SitePoint forums. I'd like to thank Noel Darlow for making this possible and providing most of the examples and information for this article.

If you have any questions or comments on this article, feel free to leave them below or join us at PHPit Forums.

« Previous: Setting up the test framework & First Test



Leave a Reply

About the author
Dennis Pallett is the main contributor to PHPit. He owns several websites, including ASPit and Chill2Music. He is currently still studying.
Article Index
  1. Setting up the test framework & First Test
  2. Applying TDD to create our Biter class
Bookmark Article
Download Article
PDF
Download this article as a PDF file