Getting Started with PHPUnit

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

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Tim

    I am using the SimpleTest Framework (http://www.simpletest.org/)

    It gives some more functionalities, is much more easy to use and makes more sense for a webdeveloper, because it offers methods to test forms and html output (like login on a website) and not only PHP classes.

    • Michelle

      Oh ok, cool. I’ll try it out too one of these days! :)

  • http://www.fuzzfree.com FuzzFree web dev gr

    Same here, I am using simpletest because I find it easier to work (but phpunit is widely adopted in php5 projects – still “beta” in simpletest).

  • http://www.phpassionate.com Lineke Kerckhoffs-Willems

    I have used both SimpleTest and PHPUnit and according to my experiences there is no real reason not to use PHPUnit. It is widely used in the PHP community and if you want to do functional/integration testing, you can use Selenium. I’d like to know what you (Tim and FuzzFree) think are the main advantages of using SimpleTest over PHPUnit.

    Michelle, great article. Love to hear your thought on SimpleTest when you get the chance to use that. I think it would be worthwile to publish an article about that too. I might even do that myself :)

    • http://www.fuzzfree.com FuzzFree

      I just found SimpleTest easier to work/get started (I quickly integreated ST into my app and wrote my first test)… I like also the internal browser functionality.

      PHPUnit was a bit “harder” for me to learn/get started (but I see all over that is the “standard” for php testing, it is more mature and has more features).

  • Dennis Becker

    Never, never use the Selenium implementation within PHPUnit. Sebastian Bergmann will not support it in future releases and hopes to remove it someday. This goes way beyond unit testing at all.

    Even though using Selenium 2 (with Google’s WebDriver) is much more convinient to use.

  • Volker

    Nice introduction!
    You don’t need the ‘require_once “PHPUnit/Autoload.php”;’ for everything to work :)

    For simpletest: Advising someone to start a project with it is, in my opinion, harmful. Simpletest is pretty much (last alpha release 5 month ago) and offers so much less then phpunit. It doesn’t even integrate well with any current Continuous Integration server like Jenkins as it doesn’t produce a junit.xml file, nor does it have any IDE support, only a very basic mocking functionality (where phpunit offers 3 mature choices) and no code coverage analysis.

    I’m sorry to highjack your blog for this but i consider the advice really hurtful to developers ;) I’d urge people to maybe have a look at http://stackoverflow.com/questions/4624093/what-unit-testing-in-php-to-start/ and related discussions before starting out with simple test :)

  • http://stripbandunk.com/ Eko Kurniawan Khannedy

    nice introductions for phpunit :D

  • http://maher.sallam.me Maher Sallam

    Great introduction. If anyone wants an easy way to automatically run tests while developing, you should check out the PHPUnit guard:
    https://github.com/Maher4Ever/guard-phpunit

  • Cezar Rosa

    Nice article.
    You can use PHPsrc, a tool to integrate with Eclipse (http://www.phpsrc.org/)

  • Moshe Teutsch

    Almost all of PHPUnit’s methods are static, so, for example, $this->assertEquals($expected, $actual) should be self::assertEquals($expected, $actual). PHP won’t generate an error if you use the former call, but it’s best practice to use the correct syntax.

    Great article!

    • Michelle

      Thanks for the tips! :)

    • Ryan

      There’s nothing about that in the PHPUnit documentation. Everything is presented as $this.

  • http://www.amitpatil.me Amit

    Michelle Michelle Michelle thank u so much for this startup tutorial….i spend 2 hours reading on phpunit website. but that didnt make any sense. ur tutorial is simple and easy to understand even for a dumb like me…thanks

    • Michelle

      I’m glad that I could help someone! Good luck in your future development :)

  • madi

    I don’t know how to install PEAR library into XAMPP,windows.
    Please kindly show me some links to reference

  • oweceej

    This was a big help to me, thanks for taking the time to publish it.

  • Lza

    raelly useful tutorial. Helped a lot to undestand how phpunit works. Thanx.

  • Florin

    Hi Michelle, I would like your help in setting an automated testing for a website, and I have no idea where to start. I have phpunit, selenium webdriver and I need a way to emulate the steps a user will make in order to login on a website. All I found on the internet was a little hard to put 1+1 together.

  • http://gavk.co.uk Gav

    Michelle – great tutorial! Simple yet effective, this is probably one of the better guides to using TDD. Keep it up! :)