PHP Unit testing with PHPUnit






Unit testing in PHP is easy and does not take much time. Below I have written a tutorial for introduction to Unit testing using PHPUnit.

Let's create a Math class with 2 methods viz. add and multiply. We will create this class as well as test cases for it. Actually first we will create the test case for add method and then the method itself. We'll repeat this for multiply method.

Creating the test case for Math::add():
Requirement: add takes 2 parameters and returns the sum of these two parameters

Test case

So we start with <?php
Then next we have require_once statement to our future class file.
Then we create a new class MathTest which extends PHPUnit_Framework_TestCase . This is very important.
Then we override 2 methods from parent class. For now I am leaving these empty and we'll come to this later.
Then we create the testAdd method. This will be the actual test. These “test cases” always begin with the word test.
Within this method we instantiate Math class. Create 2 variables to pass to add method as arguments and 1 variable that is the expected output.
The next line actually is simpler than it looks. It basically calls the Math::add method with 2 arguments and compares with expected output.

We've not created Math class, but I'll run this test case anyway just to see what happens.



The font in the image might be small but it says
PHP Warning:  require_once(Math.php): failed to open stream: No such file or directory in /home/amit/unittest/MathTest.php on line 3
PHP Fatal error:  require_once(): Failed opening required 'Math.php' (include_path='.:/usr/share/php:/usr/share/pear') in /home/amit/unittest/MathTest.php on line 3
Which means it could not find the class Math.

Now let's create the Math class with and add method.
This is a very simple class.

Now let's save this as Math.php along side the MathTest.php and run the test.
Notice there is a dot somewhere in the middle from top on left hand side. This is actually saying that the test was running. The final line says (that everything is) OK.

So this was the first test case. Again, just for demo, let's change the expected value to 6 but keep the arguments same so that our test case will fail.
When we run the test again, the output is something like:
See it says FAILURES at lots of places.

Now let's modify the test case again.

What I did is this time I changed expected value back to 5 and created a new variable $notexpected and set it to 6. Then I've used assertNotEquals to make sure that the result does not match $notexpected.

When we run the test.

1 test, 2 assertions. This means we can write as many assertions in a test case as we want. I'll go ahead and modify the test case again to demonstrate this further.

This time I've created 6 assertions inside one test case.

When we run this test:

Similarly let's develop the multiply method. First the test case.
Writing this test case took about 1 minute, though this is simple example, the most complicated one will also take not more than a few minutes, if you know what you are doing.
We can create more assertions inside the testAdd method but it is a good Idea to create a different test case for every method in your class.
Also you will notice that, for 2nd assertion I save the value that my new mthod will return to $result variable and use that to assert. And in 3rd assertion I've not created the expected and notexpected variables, but directly substituted their operations.

Now let's create the method.

Pretty simple. Now let's run the test.

Great, all tests passed. Notice the 2 dots instead of one. This indicates that it ran 2 tests.

You may think that to test a 3 line method, we have created such a long test case. Writing that test case actually took more lines than writing the program. But in reality, how many of your methods are 3 lines long? And instead of opening urls and waiting for the pages to load everytime we need to test, we can just run the test case which executes all the tests sequentially and tells us what problem there is.