Getting Started with PHPUnit

Share this article

This post is outdated – for a more up-to-date introduction, please see the recently published re-introduction!


Most people know that testing your websites is a good idea, but after some time testing can become tedious. What if a lot of this testing process could be automated so you don’t have to go trough every function manually, time after time, to ensure that it still works after updating your code? This is where unit testing comes in, to automate the testing process.

Unit testing makes it easier, and above all safer, to modify your code because it catches any irregularities in the behavior (i.e. bugs) that may be introduced with the new code. In this article you will learn the absolute basics of unit testing with PHPUnit and how easy it is to get started using it as I guide you trough the process of writing your first test.

Before you can start writing your first unit test, you need to have PHPUnit installed. It can easily be installed using the PEAR installer, and the process is documented in PHPUnit’s online manual at www.phpunit.de/manual/current/en/installation.html.

Writing Your First Test

Now it’s time to get your hands dirty writing your first test! To get started, you need something to test, so for the first example I’ve written a very simple PHP class representing a user:

<?php
class User {
    protected $name;

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
    }

    public function talk() {
        return "Hello world!";
    }
}

Let’s say you want to ensure that the user always says hello; it would be devastating for example if she started meowing like a cat all of a sudden!

For this you need to make a new test class, which I’ve arbitrarily named UserTest. It doesn’t matter what you call your test classes but it’s generally a good idea to name them after the classes you’re testing.

To create the test class, you need to include the class you’re testing as well as PHPUnit’s autoloading functionality. Then you define the test class which extends PHPUnit_Framework_TestCase.

<?php
require_once "PHPUnit/Autoload.php";
require_once "User.php";

class UserTest extends PHPUnit_Framework_TestCase
{
}

This is the class in which you will write your tests, and every test will have its own method.

The assertEquals() method defined in PHPUnit_Framework_TestCase does just what you would assume, it asserts whether something is equal or not. Since UserTest is a subclass of PHPUnit_Framework_TestCase, you can use it with $this.

To ensure the user says an appropriate greeting, write the following method:

<?php
...
class UserTest extends PHPUnit_Framework_TestCase
{
    // test the talk method
    public function testTalk() {
        // make an instance of the user
        $user = new User();

        // use assertEquals to ensure the greeting is what you
        $expected = "Hello world!";
        $actual = $user->talk();
        $this->assertEquals($expected, $actual);
    }
}

Setup and Teardown

Needing to setup a new user in every test method can become quite tedious. This is where PHPUnit’s fixtures can help. A fixture is when you setup a certain state and after every test the state is reset back to the way it was. How does this work?

Let’s say you have your object $user and you override the inherited setUp() method:

<?php
...
class UserTest extends PHPUnit_Framework_TestCase
{
    protected $user;
...
    protected function setUp() {
        $this->user = new User();
        $this->user->setName("Tom");
    }
}

Here you’ve instantiated your user and set his name to Tom.

When you are done with all the tests you might want to unset the user; for this you can override the tearDown() method:

<?php
...
class UserTest extends PHPUnit_Framework_TestCase
{
...
    protected function tearDown() {
        unset($this->user);
    }
...
}

The setUp() and tearDown() methods are called by PHPUnit before and after each test, so you can skip instantiating the user in the test method. testTalk() now becomes:

<?php
...
class UserTest extends PHPUnit_Framework_TestCase
{
...
    public function testTalk() {
        $expected = "Hello world!";
        $actual = $this->user->talk();
        $this->assertEquals($expected, $actual);
    }
}

Running Your Tests

Now that you have a test class that defines all your tests, wouldn’t it be nice to run them? If you have successfully installed everything, you should be able to simply run the tests from a terminal.

michelle@testbed:~$ phpunit UnitTest UserTest.php
PHPUnit 3.6.3 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 5.75Mb

OK (1 test, 1 assertion)

Congratulations! You have now written and run your first unit test with PHPUnit!

Do you see the little dot there? For every test run there will be a character indicating the result. The characters are as follows:

  • . – Printed when a test succeeds.
  • F – Printed when an assertion fails.
  • E – Printed when an error occurs while running the test.
  • S – Printed when the test has been skipped.
  • I – Printed when the test is marked as being incomplete.

Right now the two most important ones you have to worry about are the dot and the F, as these indicate whether your test was a success or failure.

When a Test Fails

So, what happens when a test fails? Let’s change the User so that they actually say something completely unexpected, like “blubb”.

<?php
class User {
...
    public function talk() {
        return "blubb";
    }
}

Now run the test as you did before.

michelle@testbed:~$ phpunit UnitTest UserTest.php
PHPUnit 3.6.3 by Sebastian Bergmann.

F

Time: 0 seconds, Memory: 5.75Mb

There was 1 failure:

1) UserTest::testTalk
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-Hello World!
+blubb

/PHPUnit introduction/tests/UserTest.php:23

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

As you can see there’s the F symbol to indicate failure. There’s also more information about the failure where you can see that it failed asserting the two strings were equal; it expected “Hello World!” but got “blubb”.

Summary

In this article you discovered that it isn’t so difficult to get started with unit-testing. The basics are very simple. However, there is a lot more to unit-testing than meets the eye. This simple test situation should be plenty to get you started writing your own tests, but try expanding it, getting errors and failing the test. Try expanding the User class and writing additional tests for it. How about adding a height, hair_color, or birthday property?

A few useful tips I can offer that will help you along the way are:

  • Try calling phpunit --help in the terminal to see what you can do with PHPUnit.
  • If you’re wondering how to test something specific, the PHPUnit manual is actually very good. I briefly mentioned fixtures, and there’s a complete description of them in the manual.
  • The manual section covering assertions really rocks when you’re just starting out. Make sure to check it out.

If you want to download the test code from this article to experiment with, it’s available at GitHub to do as you please.

I hope this tutorial helped you to get started with PHPUnit. Try it out, learn from your mistakes, don’t be afraid to ask any questions, and above all have fun!

Editor Note 19 Oct 2012: The accompanying code available on GitHub has been updated to use Composer to download the PHPUnit dependency. The require statement has been changed to call vendor/autoload.php to procure an autoloader. Running the test can be done by navigating into the tests directory and invoking ../vendor/bin/phpunit UnitTest UserTest.php.
Image via Archipoch / Shutterstock

Michelle SanverMichelle Sanver
View Author

Michelle Sanver is one of the rare people out there, a female geek. Her geeky interests include Macs and programming, especially PHP which has been one of her biggest hobbies since basically forever. In 2010, Michelle created Jippey where she works as a web/iOS developer.

Intermediate
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week