So, your code is ready, or so you think. Now it is time for testing.
You fire up the browser and go through each feature. That is when you find an error.
You go back to the code, do some changes and test again, only to discover your fix has introduced another error.
Deja-vu? I bet yes.
It turns out there is, and it goes by the name of Unit Testing.
Unit Testing is a technique to automatically test your code. Basically you write instructions on how your code should behave, then, after each change, a program grabs those instructions and, in seconds, ensures your code behaves accordingly.
Some people, think unit tests are so useful that they write the tests before any line of code has been written. That methodology is know as Test Driven Development (TDD).
TDD is a fundamental step stone in Agile Development because it forces you to think about the application design and interaction between different components before starting to code and so achieving superior technical design.
We will talk about Unit Testing with PHPUnit but the principles apply to all tools.
Enough talking it is time to get our hands dirty!
As with any tool before you can use it it needs to be installed. You should be able to find PHPUnit in your Linux distribution repositories, if not, or if you are running Windows you can install it with PEAR.
PEAR is the PHP Extension and Application Repository, a repository of PHP extensions and applications ready to use.
You can test the installation by typing
You should get some output similar to this one
PHPUnit 3.6.12 by Sebastian Bergmann.
How to test
You should test each unit of code individually. A unit of code is usually a class.
This means that each class should be tested in separate and one at a time.
This principle forces us to use Dependency Injection so that we can test only one unit of code at a time.
Although testing every line of code is good, most of the times it is not needed, start by focusing on the most important parts of your code, the ones that absolutely need to be error free.
After that is covered you can extend your tests to less important parts of the application.
Keep in mid that testing is an art, and having covered all the lines of your code with tests does not ensure the program is free of errors, you need to think about the border cases and try to test every possible action.
you can test the happy flow or what the user is expected to do and a few obvious error cases, like the user has passed a string instead of a number.
The purpose of testing is to give you a sense of confidence in the behavior of your code allowing you to make changes knowing the behavior is unchanged
Anatomy of a test
PHPUnit organizes tests in something called a Test Case. A Test Case is nothing more than class used to group related tests.
To take full advantage of what PHPUnit has to offer our Test Case needs to extend the class PHPUnit_Framework_TestCase.
This class besides assertions, that we will talk about later in this article, has two important methods called setUp() and tearDown().
The setUp() method is used to initialize the pre-requesites common to all our Test Case tests and it is executed before each individual test.
On the other hand the tearDown() method is used to clean up resources and is executed after each test.
You can use the setup() method to create file pointers or open database connections and the tearDown() method to close then
Tests are regular class methods that start with the word test, if your method does not start with test PHPUnit will not execute it. This allows for greater flexibility as we can structure our Test Case in the way that is most convenient for us.
As a convention our Test Case class name should end with TestCase and the file name with Test. So assuming we are testing a class named Magazine the Test Case class name should be MagazineTestCase and the file name should be MagazineTest.php.
It is also common to give the test method the name of the method that we are testing followed by any special condition for example
would be acceptable test method names
A simple yet important concept. An assertion is a statement that holds as true. It is through Assertions that we state the desired behavior of our code.
Each time an Assertion does not hold as true PHPUnit generates an error and marks that test as failed.
PHPUnit has a vast collection of Assertions ranging from simple checks like asserting that a value is true or false to more complex ones like asserting that two arrays are equal or that two variables hold the same object.
We are not going to discuss all assertions just head to the < title="assertions"a href="http://www.phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.assertions" target="_blank">manual and check the assertions shipped with PHPUnit.
Save it in you bookmarks, the manual is quite good and complete.
If you find that one is missing you can create it and send it back to the PHPUnit team.
Our first test
Now the fun part begins.
class MagazineTestCase extends PHPUnit_Framework_TestCase
As you can see we start by creating a class that extends the PHPUnit_Framework_TestCase
protected function setUp()
$this->object = new Magazine;
protected function tearDown()
We defined the setUp() and tearDown() methods of our test, in this case we create a new Magazine class before each test and get rid of it after each test
public function testSetAndGetNumber()
$magazine = $this->object;
// ensure we have no value to begin with
Finally we test the getnumber() and setNumber() methods of our class.
We first ensure there is no number, then we set it to 12 and ensure the getNumber() method returns 12
With this we have our first test.
Our code is well designed and throws exceptions whenever an exceptional situation is detected. Although we could wrap our test code in a try/catch statement and then assert that the exception is of the correct type it would be hard to ensure that the exception was actually thrown.
PHPUnit makes it extremly simple for us to ensure an exception was thrown, this is how:
* @expectedException InvalidArgumentException
public function testSetNumberWithWrongType()
This test method is commented with a special annotation the @expectedException. This is how we tell PHPUnit that the code should throw an exception in this case of the type InvalidArgumentException.
Through annotation we can also control the execution of the tests, the @depends annotation tells PHPUnit only to execute a test if the test that we depend on was successful
We have barely touched the surface of the Unit Testing world. In a next article we will see more advanced topics and techniques like Data Providers, Mocks, PHPUnit Configuration, Code Coverage and automatic test generation.
Meanwhile I strongly suggest you to RTFM and explore all the features PHPUnit has to offer you
I hope that by now you can understand the benefits of testing as well as being able to start writing your own tests