148 votes

Test des classes abstraites

Comment tester les méthodes concrètes d'une classe abstraite avec PHPUnit ?

Je m'attendrais à devoir créer une sorte d'objet dans le cadre du test. Cependant, je n'ai aucune idée de la meilleure pratique pour cela ou si PHPUnit le permet.

10 votes

Vous devriez peut-être envisager de modifier la réponse acceptée.

1 votes

Peut-être stackoverflow.com/a/2947823/23963 vous aidera.

248voto

Victor Farazdagi Points 1407

Le test unitaire des classes abstraites ne signifie pas nécessairement le test de l'interface, car les classes abstraites peuvent avoir des méthodes concrètes, et ces méthodes concrètes peuvent être testées.

Il n'est pas rare, lorsque l'on écrit du code de bibliothèque, d'avoir une certaine classe de base que l'on souhaite étendre dans sa couche d'application. Et si vous voulez vous assurer que le code de la bibliothèque est testé, vous avez besoin de moyens pour UT les méthodes concrètes des classes abstraites.

Personnellement, j'utilise PHPUnit, et il dispose de ce qu'on appelle des stubs et des objets fantaisie pour vous aider à tester ce genre de choses.

Directement de Manuel de PHPUnit :

abstract class AbstractClass
{
    public function concreteMethod()
    {
        return $this->abstractMethod();
    }

    public abstract function abstractMethod();
}

class AbstractClassTest extends PHPUnit_Framework_TestCase
{
    public function testConcreteMethod()
    {
        $stub = $this->getMockForAbstractClass('AbstractClass');
        $stub->expects($this->any())
             ->method('abstractMethod')
             ->will($this->returnValue(TRUE));

        $this->assertTrue($stub->concreteMethod());
    }
}

Les objets factices vous apportent plusieurs choses :

  • vous n'êtes pas obligé d'avoir une implémentation concrète de la classe abstraite, et vous pouvez vous en sortir avec un stub à la place
  • vous pouvez appeler des méthodes concrètes et affirmer qu'elles fonctionnent correctement
  • si une méthode concrète fait appel à une méthode non implémentée (abstraite), vous pouvez récupérer la valeur de retour avec la méthode PHPUnit will().

39voto

takeshin Points 16579

C'est une bonne question. Je l'ai cherchée aussi.
Heureusement, PHPUnit a déjà getMockForAbstractClass() pour ce cas, par exemple

protected function setUp()
{
    $stub = $this->getMockForAbstractClass('Some_Abstract_Class');
    $this->_object = $stub;
}

Important :

Notez que cela nécessite PHPUnit > 3.5.4. Il y avait un bug dans les versions précédentes.

Pour passer à la version la plus récente :

sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit

0 votes

Cela semble intéressant mais vous testeriez contre la maquette ? À quoi ressembleraient les tests ? Par exemple : extension de l'objet fantaisie dans le scénario de test et test contre la classe de test étendue ?

37voto

GordonM Points 14008

Il est à noter qu'à partir de PHP 7, le support de la fonction classes anonymes a été ajouté. Cela vous donne un moyen supplémentaire de mettre en place un test pour une classe abstraite, qui ne dépend pas de la fonctionnalité spécifique de PHPUnit.

class AbstractClassTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var AbstractClass
     */
    private $testedClass;

    public function setUp()
    {
        $this->testedClass = new class extends AbstractClass {

            protected function abstractMethod()
            {
                // Put a barebones implementation here
            }
        };
    }

    // Put your tests here
}

4 votes

Merci pour cela ! Utiliser une classe anonyme dans PHPUnit m'a donné beaucoup de flexibilité dans la création de mes différents tests.

1voto

Eran, votre méthode devrait fonctionner, mais elle va à l'encontre de la tendance à écrire le test avant le code réel.

Ce que je suggère, c'est d'écrire vos tests sur la fonctionnalité souhaitée d'une sous-classe non abstraite de la classe abstraite en question, puis d'écrire à la fois la classe abstraite et la sous-classe d'implémentation, et enfin d'exécuter le test.

Vos tests doivent évidemment tester les méthodes définies de la classe abstraite, mais toujours via la sous-classe.

0 votes

Je trouve que c'est une réponse arbitraire : Vous avez une classe abstraite 'A' ayant une méthode commune 'foo()'. Cette méthode 'foo()' est utilisée par toutes les classes 'B' et 'C', toutes deux dérivées de 'A'. Quelle classe choisiriez-vous pour tester 'foo()' ?

1voto

skqr Points 131

La réponse de Nelson est fausse.

Les classes abstraites ne nécessitent pas que toutes leurs méthodes soient abstraites.

Les méthodes implémentées sont celles que nous devons tester.

Ce que vous pouvez faire, c'est créer une fausse classe d'attente dans le fichier de test unitaire, lui demander d'étendre la classe abstraite et d'implémenter uniquement ce qui est nécessaire, sans aucune fonctionnalité, bien sûr, et de la tester.

A la vôtre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X