web-dev-qa-db-fra.com

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.

137
Mez

Le test unitaire des classes abstraites ne signifie pas nécessairement tester 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 si rare, lors de l'écriture de code de bibliothèque, d'avoir une certaine classe de base que vous prévoyez d'étendre dans votre couche d'application. Et si vous voulez vous assurer que le code de 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 a ce qu'on appelle des talons et des objets factices pour vous aider à tester ce genre de choses.

Directement depuis manuel 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());
    }
}

L'objet simulé vous donne plusieurs choses:

  • vous n'êtes pas obligé d'avoir une implémentation concrète de la classe abstraite et pouvez vous en sortir avec stub à la place
  • vous pouvez appeler des méthodes concrètes et affirmer qu'elles fonctionnent correctement
  • si la méthode concrète s'appuie sur une méthode non implémentée (abstraite), vous pouvez stub la valeur de retour avec la méthode will () PHPUnit
230
Victor Farazdagi

C'est une bonne question. Je le cherchais aussi.
Heureusement, PHPUnit a déjà la méthode getMockForAbstractClass() pour ce cas, par ex.

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 n bug dans les versions précédentes.

Pour mettre à niveau vers la dernière version:

Sudo pear channel-update pear.phpunit.de
Sudo pear upgrade phpunit/PHPUnit
36
takeshin

Il convient de noter qu'à partir de PHP 7 la prise en charge de classes anonymes a été ajoutée. Cela vous donne une avenue supplémentaire pour configurer un test pour une classe abstraite, une cela ne dépend pas des fonctionnalités spécifiques à 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
}
25
GordonM

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

Je suggérerais 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 devraient évidemment tester les méthodes définies de la classe abstraite, mais toujours via la sous-classe.

1
Bruno

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 de stub sur le fichier de test unitaire, lui faire étendre la classe abstraite et implémenter uniquement ce qui est requis sans aucune fonctionnalité, bien sûr, et le tester.

À votre santé.

1
skqr

Si vous ne voulez pas sous-classer la classe abstraite simplement pour effectuer un test unitaire sur les méthodes qui sont déjà implémentées dans la classe abstraite, vous pouvez essayer de voir si votre framework vous permet de mock classes abstraites.

0
hangy