In the previous article, we learned about the basic concepts of testing in general. Now, let's move on to something more practical and focus on how to write unit tests with PHPUnit.
The main goal of this tutorial, is to get yourself familiar with PHPUnit as a tool. I thought it would be a lot easier to start learning the tool itself rather than jumping directly into an example without knowing how it works.
In the next tutorial, we'll use our knowledge from this tutorial to write tests that you'd write in real life projects.
Like any other package, PHPUnit can be installed via Composer. Just run this command from a new directory:
composer require phpunit/phpunit --dev
To make sure that it was installed successfully, run it using this:
./vendor/bin/phpunit
That should list a full description of the tool instead of displaying “command not found: phpunit”.
In this case, we've installed it locally (per project). However, if you prefer to install it globaly, run this instead:
composer global require phpunit/phpunit
One last thing before we move on. I usually don't like to write the full path of the tool each time I want to use it — in this case ./vendor/bin/phpunit. I just like to write phpunit.
To do that we have two choices, either to create an alias for it or to add the path of the tool's directory to our global $PATH variable. Let's make it simple for now and create an alias with this command:
alias phpunit="./vendor/bin/phpunit"
From now on, you can run PHPUnit by just writing phpunit.
Since our focus in this tutorial is on the tool, we'll work with something very simple to make it easy to understand.
First, we need to dedicate a folder for our tests. So create a new folder and name it tests. In this folder we can have any number of test files we want. In each test file we can have any number of test cases.
So create a new test file and name it ExampleTest.php. Then, put in the following:
class ExampleTest extends PHPUnit_Framework_TestCase
{
function testAddition()
{
$this->assertEquals(4, 2+2);
}
}
Even if you know nothing about testing, it seems we're testing that 2+2 equals 4 (I know it's a little dumb test, but anything to get us going).
Before we get into any detail, let's try to run the test to see if everything is working.
You can run the test by running this command:
phpunit tests/ExampleTest.php
So, we specify the path of the test we want to run. If you instead give it the path of the directory (without a specific file), it will run all tests within that directory, which is pretty useful.
If everything is good, you'll get something similar to this:
PHPUnit 4.8.22 by Sebastian Bergmann and contributors.
.
Time: 38 ms, Memory: 3.75Mb
OK (1 test, 1 assertion)
Now, let's try to make the test fail and see what we're going to get. For example, change the assertion to this:
$this->assertEquals(4, 3+2);
If you run the test again, you'll get this time a failure message that tells you about the problem. In this case, it should say: “Failed asserting that 5 matches expected 4.”
Now, let's get back to the code and see how it works.
When you create a new test, the very first thing you need to do is to make your test class extend PHPUnit_Framework_TestCase. Among other things, this class provides us with a list of assertion methods that we use to test stuff.
PHPUnit provides us with tons of those assertion methods. In our example, we used assertEquals which, well, checks to see if two values are equal. This one takes two arguments. The first one is the expected value (it's usually hard-coded). The other one is the actual value (which we get from the class under testing).
Notice that we're not testing any class here, everything is hard-coded. Later on in this tutorial, I'll show you how to include one and use it.
You can review a full list of the available assertions from the documentation.
The good news is that we don't have to know them all. We can test most things with just a few. Here are the ones you'll use the most:
Note how we have an inverse version for each one (they usually are the same but with “Not” in the method name).
Each method you define in the test class is called a Test Case. In each one, you test a specific part of the feature you're testing.
For example, if you're testing a calculator class (let's say it's a new feature in your application), you'll create a test class (called CalculatorTest, for example). And in that test, you'll have a test case for each part, like the addition, subtraction, multiplication, and so on.
But not every method in the test class is considered a test case. PHPUnit will only run those methods that are public and their names begin with the word “test” — in this example testAddition.
Alternatively, you can use the @test annotation in the method's docblock. Like this:
/** @test */
function it_adds_two_numbers() {
}
I usually go for the second option, because I think it makes my test names cleaner and easier to read.
If you don't mark a method as a test method, PHPUnit will ignore it and it won't run. And in some cases, this is what you want. You'll use them as helper methods, mainly to remove the repetition from the test cases — DRYing your tests.
Until now, we haven't tested any class yet. As you'll see, it's no different from what we've been doing, except we're using the class's result in the assertions.
So in our example, we would create a Calculator class and test its addition feature.
You can create the class anywhere you want, but we usually put it in a src/ directory. So, create Calculator.php in that directory and put in the following:
class Calculator
{
public function add($a, $b)
{
return $a + $b;
}
}
To use this class in your tests, you have to import it first. For that you have two options. Either using the traditional require/include or using the autoloader that composer provides.
Typically we use the latter. (I assume you know how it's done, right?) But in order for that to work, we have to tell PHPUnit about it. We can do that with the bootstrap option when running PHPUnit.
Here's how you'll use it:
phpunit --bootstrap="vendor/autoload.php"
When you do that, PHPUnit will run the autoloader before each test case, which is exactly what we want.
After you import your class, you can use it in the test like this:
class ExampleTest extends PHPUnit_Framework_TestCase
{
function testAddition()
{
$calculator = new Calculator;
$result = $calculator->add(2, 2);
$this->assertEquals(4, $result);
}
}
Like any tool, PHPUnit can be configured to your needs. You can check the documentation to see what options you can configure.
Having said that, let's see the common configurations that you can start with.
In your project root, create a new XML file and name it phpunit.xml (this is what PHPUnit will look for). Then put in the following:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
bootstrap="vendor/autoload.php"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="default">
<directory>./tests/</directory>
</testsuite>
</testsuites>
</phpunit>
The documentation has a full description of each option. Nevertheless, let's review the important ones here.
Great! Now, you know almost everything you need to know to use this tool. But we didn't see any real example, yet.
In the next tutorial, we'll see the basic workflow of building and testing something from scratch!
I'm a freelance web developer. Laravel & VueJS are my main tools these days and I love building stuff using them. I write constantly on this blog to share my knowledge and thoughts on things related to web development... Let's be friends on twitter.