Skip to content

PHPUnit🔗

Create a test file in the tests folder following the same path that your source file and add the suffix Test.

For example:

  • Source file: src/Application/Command/FoobarCommandHandler
  • Test file: tests/Application/Command/FoobarCommandHandlerTest

Using Prophecy🔗

The class you want to test has dependencies:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

class FoobarCommandHandler
{
    private $foobarRepository;

    private $foobarChecker;

    public function __construct(
        FoobarRepositoryInterface $foobarRepository,
        FoobarCheckerInterface $foobarChecker
    ) {
        $this->foobarRepository = $foobarRepository;
        $this->foobarChecker = $foobarChecker;
    }

    public function handle(FoobarCommand $command)
    {
        $foobar = new Foobar($command->title);

        if (!$this->foobarChecker->check($foobar)) {
            throw new Exception();
        }

        $this->foobarRepository->add($foobar);

        return $foobar;
    }
}

Your test:

1
2
3
4
5
6
7
8
<?php

class FoobarCommandHandlerTest
{
    public function testHandle()
    {
    }
}
  1. Create an instance of the class you want to test

    1
    2
    <?php
    $handler = new FoobarCommandHandler();
    
  2. Look for dependencies and create mocks for each of them:

    1
    2
    3
    4
    5
    <?php
    $repository = $this->prophesize(FoobarRepositoryInterface::class);
    $checker = $this->prophesize(FoobarCheckerInterface::class);
    
    $handler = new FoobarCommandHandler($repository->reveal(), $checker->reveal());
    
  3. Call the method you want to test and look for parameters you need to pass

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    $repository = $this->prophesize(FoobarRepositoryInterface::class);
    $checker = $this->prophesize(FoobarCheckerInterface::class);
    
    $handler = new FoobarCommandHandler($repository->reveal(), $checker->reveal());
    
    $command = new FoobarCommand('My title');
    
    $handler->handle($command);
    
  4. Look if the method you test returns something, if so, test the return value with assertEquals

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    <?php
    $repository = $this->prophesize(FoobarRepositoryInterface::class);
    $checker = $this->prophesize(FoobarCheckerInterface::class);
    
    $handler = new FoobarCommandHandler($repository->reveal(), $checker->reveal());
    
    $command = new FoobarCommand('My title');
    
    $expected = new Foobar('MyTitle');
    
    $this->assertEquals($expected, $handler->handle($command));
    
  5. Look for methods call on your class dependencies and mock them. Check if they should be called or not, if they must return something, etc.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    // Mocks
    $repository = $this->prophesize(FoobarRepositoryInterface::class);
    $checker = $this->prophesize(FoobarCheckerInterface::class);
    
    // Tested class
    $handler = new FoobarCommandHandler($repository->reveal(), $checker->reveal());
    
    // Input
    $command = new FoobarCommand('My title');
    
    // Expected
    $expected = new Foobar('MyTitle');
    
    // Asserts
    $checker->check($expected)->shouldBeCalled()->willReturn(true);
    $repository->add($expected)->shouldBeCalled();
    $this->assertEquals($expected, $handler->handle($command));
    
  6. Run the test

  7. Test other scenarios

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // Mocks
    $repository = $this->prophesize(FoobarRepositoryInterface::class);
    $checker = $this->prophesize(FoobarCheckerInterface::class);
    
    // Tested class
    $handler = new FoobarCommandHandler($repository->reveal(), $checker->reveal());
    
    // Input
    $command = new FoobarCommand('My title');
    
    // Expected
    $expected = new Foobar('MyTitle');
    
    // Asserts
    $checker->check($expected)->shouldBeCalled()->willReturn(false);
    $repository->add($expected)->shouldNotBeCalled();
    $this->expectException(Exception::class);
    $this->assertEquals($expected, $handler->handle($command));
    

Not using Prophecy🔗

The class you want to test has no dependencies:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php

class ScoreComputer
{
    public function compute(Foobar $foobar)
    {
        if ($foobar->title === 'foobar') {
            return 100;
        }

        return $foobar->value * 0.9;
    }
}

Your test:

1
2
3
4
5
6
7
8
<?php

class ScoreComputerTest
{
    public function testCompute()
    {
    }
}
  1. Create the instance of your class

    1
    2
    <?php
    $computer = new ScoreComputer();
    
  2. Call the method you want to test and look for parameters you need to pass

    1
    2
    3
    4
    5
    6
    <?php
    $computer = new ScoreComputer();
    
    $foobar = new Foobar('foobar', 24);
    
    $computer->compute($foobar);
    
  3. Look if the method you test returns something, if so, test the return value with assertEquals

    1
    2
    3
    4
    5
    6
    <?php
    $computer = new ScoreComputer();
    
    $foobar = new Foobar('foobar', 24);
    
    $this->assertEquals(100, $computer->compute($foobar));
    
  4. Run the test

Using data providers🔗

If the method you are testing has many use cases which depend on parameters or dependencies return values, you can use data provider to cover all use cases.

  1. Put expected value and variables that can influence the result as parameters

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <?php
    
    class ScoreComputerTest
    {
        public function testCompute($expected, $title, $value)
        {
            $computer = new ScoreComputer();
    
            $foobar = new Foobar($title, $value);
    
            $this->assertEquals($expected, $computer->compute($foobar));
        }
    }
    
  2. Create a dataProvider static method to return data sets

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <?php
    
    class ScoreComputerTest
    {
        public static function provideScores()
        {
            return [
                // if title is foobar, the score will be 100 not matter the value
                [100, 'foobar', 30],
                // if title is not foobar, the score will be equal to 0.9 * the value
                [27, 'my title', 30], 
                [90, 'my title', 100], 
                [63, 'hello', 70], 
            ];
        }
    
        /**
         * @dataProvider provideScores
         */
        public function testCompute($expected, $title, $value)
        {
            $computer = new ScoreComputer();
    
            $foobar = new Foobar($title, $value);
    
            $this->assertEquals($expected, $computer->compute($foobar));
        }
    }
    

    Your test will be run 4 times with these different parameters and will cover all possibilities.

Run tests🔗

In elao projects🔗

To run your tests, use the command make test in your container.

Other way🔗

It's also useful to run your tests with the PHPUnit command-line test runner through the bin/phpunit command.

  1. Run all tests

    1
    bin/phpunit
    
  2. Run one specific test

    Use this command to run tests for specific directory or class

    1
    bin/phpunit tests/Application/Command
    
    or
    1
    bin/phpunit tests/Application/Command/FoobarCommandHandlerTest.php
    

  3. Run tests with additional options

    Use the --filter option to run a specific test method

    1
    bin/phpunit --filter 'tests\\Application\\Command\\FoobarCommandHandlerTest::testHandle'
    

    To get more 'readable' results, use the --testdox option

    1
    bin/phpunit tests/Application/Command/FoobarCommandHandlerTest.php --testdox
    
    Result:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Testing App\Tests\Application\DownloadFoobarCommandHandlerTest
    Zip Archive Factory (App\Tests\Application\DownloadFoobarCommandHandler)
    ✔ Test 1 // (extract from class name)
    ✔ Test 2
    ✔ Test 3
    
    Time: 00:04.929, Memory: 34.00 MB
    
    OK (3 tests, 12 assertions)
    

Sources🔗

Check the official PHPUnit documentation right here


Last update: December 20, 2024