Aller plus loin avec les tests unitaires

Objectifs

Apprendre à tester des exceptions PHP

Contexte

Pour aller plus loin avec l'utilisation et la maîtrise des tests unitaires au sein d'un projet Symfony, il peut être intéressant de découvrir comment tester nos exceptions PHP et utiliser correctement le système de Data Provider (ou fournisseur de données) livré avec PHPUnit.

PHPUnit offre la possibilité de tester la levée d'exceptions PHP. Ce type de test nous permettra de nous assurer que ces dernières sont correctement définies et effectivement levées en cas de problème.

Méthode

Ce test passe toujours par l'utilisation de la classe TestCase issue du framework PHPUnit. Plutôt que la méthode assertEquals(), nous utiliserons ici la méthode expectException(). Comme son nom l'indique, elle permet de s'assurer qu'une exception est bien levée en cas de mauvaise pratique.

Reprenons l'exemple de notre classe HelloWorld et ajoutons à la méthode hello() une simple exception de type InvalidArgumentException, se levant si l'argument reçu ne correspond pas à une chaîne de caractères.

La classe à tester

1
<?php
2
# src/Util/HelloWorld.php
3
namespace App\Util;
4
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
5
6
class HelloWorld {
7
    public function hello($name) {
8
        if(!is_string($name)) {
9
            throw new InvalidArgumentException("La méthode 'hello()' accepte uniquement une chaîne de caractère en entrée.");
10
        }
11
        return 'Hello ' . $name;
12
    }
13
}

Pour tester la levée de cette exception, nous créons une nouvelle classe de test « ExceptionTest » étendant la classe TestCase de PHPUnit afin d'avoir accès à la méthode expectException().

Au sein de cette classe, nous écrivons une méthode testException(), chargée de tester la levée de l'exception rédigée précédemment dans la classe HelloWorld.

Pour cela, nous créons une instance de cette classe avant d'appeler la méthode expectException(). Notez que cette dernière attend le type d'exception à tester en argument. Pour rappel, nous souhaitons, ici, tester une exception de type InvalidArgumentException.

Nous appelons enfin la méthode où l'exception est censée être levée en prenant soin de lui donner un mauvais type d'argument. Dans notre exemple, passons un entier en argument de la méthode hello() qui, je vous le rappelle, s'attend normalement à recevoir une chaîne de caractères.

La classe de test

1
<?php
2
# tests/Util/ExceptionTest.php
3
namespace Tests\Util;
4
5
use PHPUnit\Framework\TestCase;
6
use App\Util\HelloWorld;
7
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
8
9
class ExceptionTest extends TestCase
10
{
11
    public function testException()
12
    {
13
        $helloWorld = new HelloWorld();
14
        $this->expectException(InvalidArgumentException::class);
15
        $helloWorld->hello(1);
16
    }
17
}

Alternativement, il est possible d'utiliser l'annotation @expectedException pour alléger notre code.

La classe de test allégée

1
<?php
2
# tests/Util/ExceptionTest.php
3
namespace Tests\Util;
4
5
use PHPUnit\Framework\TestCase;
6
use App\Util\HelloWorld;
7
8
class ExceptionTest extends TestCase
9
{
10
    /**
11
     * @expectedException InvalidArgumentException
12
     */
13
    public function testException()
14
    {
15
        $helloWorld = new HelloWorld();
16
        $helloWorld->hello(1);
17
    }
18
}

SyntaxeÀ retenir

Concernant le test d'exceptions PHP, il est essentiel de retenir la méthode expectException() issue de la classe TestCase à faire étendre à notre classe de test. Souvenez-vous également que cette méthode prend le type d'exception à lever en argument.

Il est également nécessaire de provoquer volontairement la levée de l'exception au sein de la méthode de test pour valider l'assertion.

Enfin, l'annotation @expectedException suivie par le type d'exception testé peut remplacer l'appel de la méthode expectException().