How To Write A Test
By Giorgio Sironi
Extensively testing a web application is the only way to make sure that the code you have written really works. Formal proofs of correctness are impossible or impractical to put together for the majority of computer programs. Therefore, actually running code in a sandbox under controlled conditions is the way to uncover bugs and drive the development of new features.
Of course, manual testing cannot be totally substituted by automated approaches, but automating a large part of an application’s tests leads to greater testing frequency, and quicker discovery of issues and regression.
Automated testing is based on the concept of test cases (classes in PHPUnit’s case) that compose a complete test suite. This suite, or a subset of it, can be run at will to check the production code correctness.
In this approach, the simplest and most effective way to write tests is to write code—simple code, but with the mandatory expressiveness of imperative languages that should give you the needed freedom.
Besides the quality assurance side of testing, there is also the advantage in feedback that a good test suite provides. The more fine-grained the tests are, the more internal quality is put under “the lens”. Clean code is easy to test, while you can’t get away with technical debt if you have to write automated tests at the same time.
Tests are the first users of your code. They will tell you much about its simplicity of use, the isolation from component dependencies and the side effects that may arise.
Installation
In the first part of this DZone Refcard, we’ll test array_sum(), a simple, native PHP function that computes the sum of values in an array. The purpose of this first test is to introduce the mechanics of PHPUnit usage.
Before writing a test at all, we need PHPUnit. You can simply grab it via its PEAR channel:
sudo pear channel-discover pear.phpunit.de
sudo pear channel-discover ... # other channels
sudo pear install phpunit/PHPUnit
sudo pecl install xdebug # for code coverage
The other channels where PHPUnit pulls components from may change in the future, so refer to the official documentation (http://phpunit.de/manual). This DZone Refcard is updated to the 3.5 version.
The first test
Here is how a test case looks like:
<?php
class ArraySumTest extends PHPUnit_Framework_TestCase
{
public function testSumTheValuesOfAnEmptyArray()
{
$sum = array_sum(array());
$this->assertEquals(0, $sum, “The sum of an empty array is computed
as $sum.”);
}
}
Essentially, this is a class that extends PHPUnit_Framework_ TestCase so that it can be run by the /usr/bin/phpunit script. Here is a sample output:
The methods whose names start with ‘test’ are executed, one at a time, on a different instance of this Test Case. You can execute whichever code you prefer in order to produce a set of results to confront with the ones you expect.
You can use methods on the Test Case that start with ‘assert’ to execute checks on the result of your computations that will ensure the system is behaving correctly. PHPUnit provides many simple assertion methods, but you can always define your own by adding private methods.
Executing phpunit filename.php from the command line would run the test. You can also run all the tests in a certain folder (subfolders included) simply by passing a path to the directory. This was the simplest test we could possibly write: it will provide good practice to start with and you can augment the complexity as you gain confidence about the System Under Test (SUT).
Now that we are capable of running a test on your machine, let’s gain confidence and expand the test a bit:
<?php
class ArraySumTest extends PHPUnit_Framework_TestCase
{
public function testSumTheValuesOfAnEmptyArray()
{
$sum = array_sum(array());
$this->assertEquals(0, $sum);
}
public function testSumTheValuesOfAnArrayWithOneValue()
{
$sum = array_sum(array(42));
$this->assertEquals(42, $sum);
}
public function testSumTheValuesOfAnArrayWithManyElements()
{
$sum = array_sum(array(1, 2, 3, 4, 5, 6));
$this->assertEquals(21, $sum);
}
public function testSumTheValuesOfAnArrayWithFloatValues()
{
$sum = array_sum(array(1, 2.5));
$this->assertEquals(3.5, $sum);
}
}
A failing test
Here is a failing test instead. We expect that array_sum works recursively by summing up all the values in internal arrays:
<?php
class ArraySumTest extends PHPUnit_Framework_TestCase
{
// ...
public function testSumsRecursively()
{
$sum = array_sum(array(1, array(2, 3)));
$this->assertEquals(6, $sum);
}
}
When run, this test gives the following result:
We were asserting that the production code performed a task that it couldn’t. The test tells us it is not living up to our expectations.
Before diving into PHPUnit’s features, I want to highlight some methods that complement assertions in the flow control of PHPUnit.
MethodEffect$this->fail($message = '')Will instantly make the test fail, like in the case an assertion fails.$this->markTestSkipped()Tells PHPUnit that this test should be interrupted and marks it with an (S) in the results.$this->markTestIncomplete()Tells PHPUnit that this test is incomplete and shouldn't be run either. It will be marked with an (i) in the results and will turn the green bar of PHPUnit into an orange one.
{{ parent.title || parent.header.title}}
{{ parent.tldr }}
{{ parent.linkDescription }}
{{ parent.urlSource.name }}