Skip to content

PHP Unit Test

Installation & Configuration

Dev-Only Installation

PowerShell
composer require --dev phpunit/phpunit
JSON
1
2
3
    "require-dev": {
        "phpunit/phpunit": "<version>"
    }

Config

PHPUnit can be configured in a XML file called phpunit.xml:

XML
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true">

    <testsuites>
        <testsuit name="App\\Tests">
            <directory>./test<directory>
        </testsuit>
    </testsuites>

    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./src</directory>
        </whitelist>
    </filter>
</phpunit>

Testing

Test Structure

PHPUnit tests are grouped in classes suffixed with Test. Each class extends PHPUnit\Framework\TestCase.
A test is a method of a test class prefixed with test.
PHPUnit is executed from the command line with vendor/bin/phpunit --colors.

PHP
1
2
3
4
5
6
7
8
9
namespace App;

class Filter
{
    public function isEmail(string $email): bool
    {
        // @todo implement
    }
}
PHP
namespace App\Test;
use PHPUnit\Framework\TestCase;
use App\Filter;

class FilterTest extends TestCase
{
    public function testValidMail()
    {
        $filter = new Filter();
        $this->assertTrue($filter->isEmail("foo@bar.com"));
    }

    public function testInvalidEmail()
    {
        $filter = new Filter();
        $this->assertFalse($filter->idEmail("foo"));
    }
}

PHPUnit Assertions

  • asseretTrue(): verifies that the element is true
  • assertFalse(): verifies that the element is false
  • assertEmpty(): verifies that the element is empty
  • assertEquals(): verifies that the two elements are equal
  • assertGreaterThan(): verifies that the element is greater than ...
  • assertContains(): verifies that the element is contained in an array
  • assertInstanceOf(): verifies that the element is an instance of a specific class
  • assertArrayHasKey(mixed $key, array $array): verify that a specific key is in the array

PHPUnit Testing Exceptions

PHP
public function testAggiungiEsameException(string $esame)
{
    $this->expectException(Exception::class);
    $this->expectExceptionMessage("exception_message");

    // execute code that should throw an exception
}

// https://github.com/sebastianbergmann/phpunit/issues/2484#issuecomment-648822531
public function testExceptionNotThrown()
{
    $exceptionWasThrown = false;

    try
    {
        // code that should succeed
    }
    catch (EsameException $e)
    {
        $exceptionWasThrown = true;
    }

    $this->assertFalse($exceptionWasThrown);
}

// same as

/**
* @doesNotPerformAssertions
*/
public function testNoExceptions(string $esame)
{
    // code that should succeed (exceptions will make the test fail)
}

Test Setup & Teardown (Example)

PHP
class ClassTest extends TestCase
{
    // initialize the test
    public function setUp(): void
    {
        file_put_contents("/tmp/foo", "Test")
    }

    // reset the test
    public function tearDown(): void
    {
        unlink("/tmp/foo")
    }

    public function testFoo()
    {
        // use temp file
    }
}

Note: setUp() and tearDown() are called before and after each test method.

Data Provider

PHP
class DataTest extends TestCase
{
    /**
    * @dataProvider provider
    */
    public function testAdd($a, $b, $expected)
    {
        $this->assertEquals($expected, $a + $b);
    }

    // test receives array contents as input
    public function provider()
    {
        // must return array of arrays
        return [
            [0, 0, 0],
            [0, 1, 1]
        ];
    }

    // test receives array of arrays as input
    public function provideArrayOfArrays()
    {
        return [
            [
                [
                    [0, 0, 0],
                    [0, 1, 1]
                ]
            ]
        ];
    }
}

Mock Objects

PHP
class UnitTest extends TestCase
{
    public function setUp()
    {
        // names of mock are independent from tested class variables
        $this->mock = $this->createMock(ClassName::class);  // create a mock object of a class
        $this->returned = $this->createMock(ClassName::class);  // mock of returned object

        $this->mock->method("methodName")  // simulate method on mock
            ->with($this->equalTo(param), ...)  // specify input params (one param per equalTo)
            ->willReturn($this->returned);  // specify return value
    }

    public function testMethod()
    {
        $this->mock
        ->method("methodName")
        ->with($this->equalTo($arg))  // arg passed to the method
        ->willReturn(value);  // actual return value for THIS case
        // or
        ->will($this->throwException(new Exception()));  // method will throw exception

        // assertions
    }
}

Code Coverage (needs XDebug)

PowerShell
vendor/bin/phpunit --coverage-text  # code coverage analysis in the terminal