An Introduction to PHPUnit Testing

Introduction: What is Automated Testing?

As an application grows, manually testing every feature after every change becomes time-consuming and unreliable. Automated testing is the practice of writing code that tests your application code. This provides a safety net, allowing you to refactor and add new features with confidence, knowing that your test suite will immediately alert you if a change breaks existing functionality.

In PHP, the industry standard for this is PHPUnit. A "unit test" is a piece of code that tests a small, isolated "unit" of your application—typically a single method within a class. This chapter will introduce the basics of setting up PHPUnit and writing your first test case.


Setting up PHPUnit with Composer

Integrating PHPUnit into our project is a straightforward process handled by Composer. We install it as a "development dependency," which means it will only be installed on our development machines and not on the production server.

To install it, you run the following command from the root directory of your project:

composer require --dev phpunit/phpunit

This command will download the PHPUnit library and add it to the require-dev section of your composer.json file. It's also a best practice to create a phpunit.xml.dist file in your project's root. This configuration file tells PHPUnit where to find your tests and how to run them.

Writing Your First Test Case Writing a unit test involves creating a special PHP class that checks the functionality of another class. The test class is typically named after the class it is testing, with a Test suffix. Inside the test class, we write public methods that begin with the word test. The core of any test is an assertion—a special method that checks if a condition is true.

A Simple Class to Test

First, let's create a simple Calculator class that we want to test.

<?php
// in classes/Calculator.php
class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

The PHPUnit Test Case Now, we create the test class, which must extend the PHPUnit\Framework\TestCase class. We create a test method that calls the add() method and then uses assertEquals() to assert that the result is what we expect.

<?php
// in tests/CalculatorTest.php
use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase
{
    public function testAdd()
    {
        // 1. Setup: Create an instance of the class we want to test.
        $calculator = new Calculator();

        // 2. Action: Call the method we want to test.
        $result = $calculator->add(2, 3);

        // 3. Assertion: Check if the result is the expected value.
        $this->assertEquals(5, $result, "2 + 3 should equal 5");
    }
}

Running Tests

Once you have written your test case, running it is a simple command-line operation. From the root directory of your project, you execute the phpunit script that Composer installed for you.

vendor/bin/phpunit

Setting up PHPUnit with Composer

Integrating PHPUnit into our project is a straightforward process handled by Composer. We install it as a "development dependency," which means it will only be installed on our development machines and not on the production server.

To install it, you run the following command from the root directory of your project:

composer require --dev phpunit/phpunit

This command will download the PHPUnit library and add it to the require-dev section of your composer.json file. It's also a best practice to create a phpunit.xml.dist file in your project's root. This configuration file tells PHPUnit where to find your tests and how to run them.

Writing Your First Test Case

Writing a unit test involves creating a special PHP class that checks the functionality of another class. The test class is typically named after the class it is testing, with a Test suffix. Inside the test class, we write public methods that begin with the word test. The core of any test is an assertion—a special method that checks if a condition is true.

A Simple Class to Test First, let's create a simple Calculator class that we want to test.

PHP

<?php
// in classes/Calculator.php
class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

The PHPUnit Test Case

Now, we create the test class, which must extend the PHPUnit\Framework\TestCase class. We create a test method that calls the add() method and then uses assertEquals() to assert that the result is what we expect.

PHP

<?php
// in tests/CalculatorTest.php
use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase
{
    public function testAdd()
    {
        // 1. Setup: Create an instance of the class we want to test.
        $calculator = new Calculator();

        // 2. Action: Call the method we want to test.
        $result = $calculator->add(2, 3);

        // 3. Assertion: Check if the result is the expected value.
        $this->assertEquals(5, $result, "2 + 3 should equal 5");
    }
}

Running Tests

Once you have written your test case, running it is a simple command-line operation. From the root directory of your project, you execute the phpunit script that Composer installed for you.

Bash

vendor/bin/phpunit

If all tests pass, you'll get a simple confirmation. If a test fails, PHPUnit will give you a detailed report, showing exactly which test failed, on which line, and why.

Successful Output:

OK (1 test, 1 assertion)

Failure Output:

FAILED
Tests: 1, Assertions: 1, Failures: 1.

1) CalculatorTest::testAdd
2 + 3 should equal 5
Failed asserting that 6 matches expected 5.

/path/to/project/tests/CalculatorTest.php:15

Conclusion: The Confidence to Refactor

An automated test suite is one of the most valuable assets a software project can have. It acts as a safety net, constantly verifying that the core components of your application are behaving exactly as you expect. The real benefit of this safety net is that it gives you the confidence to refactor and improve your code without the fear of introducing subtle, unforeseen bugs.

Shopping summary

Item

SubTotal: £

Empty Basket

this is a hidden panel

Completed in 39 milliseconds

Completed in 39 milliseconds

This is the top Panel

This is the bottom Panel