Some people have asked me to write something about testing, so I’ve decided to make this post and share some phpunit tips that I’ve learn.
This is not meant to be another tutorial of how to start writing your own tests with phpunit. Well, actually it is, but the purpose of my post is to explain you how to deal with real scenarios. If you try to search for phpunit examples, most places will show you how to create very simple test cases, but I haven’t seen many places explaining how to do more complex things. That’s exactly the purpose of this article. Moreover, If you think something’s missing, I encourage you to ask me about it, and I’ll try to append it to the post, or if it’s a big enough subject, I’ll create a whole new article about it.
Let’s begin from a very simple case, and we’ll get into something a bit more complicated step by step.
I assume that you already know what’s PHPUnit, and some basic concepts of how to use it, like for instance the dataproviders or mocks. If you think that you need some help to get started, have a look at PHPUnit’s official page and feel free to ask me, if needed.
Happy case in PHPUnit: Imagine you have an isolated class and you wanna test some of its methods.
/** * This code has been taken just as an example, from: http://snipplr.com/view.php?codeview&id=9024 */ class TheDeveloperWorldIsYours { public static function generateUrlFromText($strText) { $strText = preg_replace('/[^A-Za-z0-9-]/', ' ', $strText); $strText = preg_replace('/ +/', ' ', $strText); $strText = trim($strText); $strText = str_replace(' ', '-', $strText); $strText = preg_replace('/-+/', '-', $strText); $strText = strtolower($strText); return $strText; } }
How would you test that? This might be an attempt:
/** * TheDeveloperWorldIsYours_Test * * @uses PHPUnit_Framework_TestCase */ class TheDeveloperWorldIsYours_Test extends PHPUnit_Framework_TestCase { public function setUp() { } protected static $inputs = array( array(' string with many spaces ', 'string-with-many-spaces'), array('stríng wïth wêird Àccents', 'str-ng-w-th-w-ird-ccents'), array('$peci4l: ch%r·ct3r$.', 'peci4l-ch-r-ct3r'), array('nice-string', 'nice-string'), array('testing+with+phpunit-is-cool', 'testing-with-phpunit-is-cool') ); public static function providerFormat() { return self::$inputs; } /** * testFormat * Ensure that the string is being properly cleaned * * @dataProvider providerFormat * @param mixed $input * @param mixed $result * @access public * @return void */ public function testFormat($input, $result) { $this->assertEquals($result, TheDeveloperWorldIsYours::generateUrlFromText($input)); } }
I assume that you have already set up some boostrap that takes care of including the required files (in this case, we just need to include the file where the class TheDeveloperWorldIsYours before executing the test).
If you run the test file with PHPUnit, you’ll notice that all the tests are passing, and you might want to add some corner cases to feel more comfortable, such as very long strings, empty strings, numbers and so. However, that’s out of the scope of this post (I could create a whole article about it). Nobody would know better than you the casuistic of your application, and you are the one responsible to add all the missing tests in each case.
So, in this example, we have the best scenario: The method is public, and even static, so we don’t need to instantiate the class in order to test the method. Also, the class doesn’t inherits from any other class, so we don’t have to worry about including all the required files.
Now, let’s assume we had the following scenario:
class TheDeveloperWorldIsYours extends Some_Parent_Class { protected function generateUrlFromText($strText) { $strText = preg_replace('/[^A-Za-z0-9-]/', ' ', $strText); $strText = preg_replace('/ +/', ' ', $strText); $strText = trim($strText); $strText = str_replace(' ', '-', $strText); $strText = preg_replace('/-+/', '-', $strText); $strText = strtolower($strText); if($strText === '') { die('Unable to generate a valid url from the given input'); } return $strText; } }