web-dev-qa-db-fra.com

Existe-t-il un exemple réel de la manière dont setUp () et tearDown () doivent être utilisés dans PHPUnit?

Les méthodes setUp() et tearDown() sont appelées avant et après chaque test. Mais vraiment, y a-t-il un vrai exemple Word sur pourquoi devrais-je en avoir besoin?

En inspectant les tests d'autres personnes, je vois toujours quelque chose comme:

public function setUp()
{
    $this->testsub = new TestSubject();
}

public function tearDown()
{
    unset($this->testsub);
}

public function testSomething()
{
    $this->assertSame('foo', $this->testsub->getFoo());
}

Bien sûr, il n'y a pratiquement aucune différence entre cette méthode et la "vieille" méthode de variable locale.

25
gremo

Si vous faites chaque méthode de test individuellement, votre code de test partagera un grand nombre de lignes qui créent simplement l'objet à tester. Ce code partagé peut (mais pas DEVRAIT) entrer dans la méthode d'installation.

Tout ce qui doit être fait pour créer l'objet à tester est ensuite inséré dans la méthode de configuration, par exemple en créant des objets fictifs injectés dans le constructeur de l'objet testé.

Rien de tout cela ne doit être supprimé, car le prochain appel à l’installation initialisera les variables de membre de classe avec un nouvel ensemble d’objets.

La seule chose qui nécessite d'être démontée est si votre test laisse quelque chose en arrière, comme des fichiers créés ou des entrées de base de données. Ce n'est vraiment pas une très bonne idée d'écrire des tests qui font de telles choses, mais à un moment donné, vous ne pouvez plus résumer et devez toucher des éléments comme le disque dur, la base de données ou le réseau réel.

Il faut donc beaucoup plus de configuration que de démontage et je supprime toujours la méthode de démontage s’il n’ya pas de travail à faire pour ce test.

En ce qui concerne les moquages, je travaille comme ceci:

private $_mockedService;
private $_object;
protected function setUp()
{
    $this->_mockedService = $this->getMock('My_Service_Class');
    $this->_object = new Tested_Class($this->_mockService);
}

public function testStuff()
{
    $this->_mockedService->expects($this->any())->method('foo')->will($this->returnValue('bar'));
    $this->assertEquals('barbar', $this->_object->getStuffFromServiceAndDouble());
}
27
Sven

Vous pouvez instancier plusieurs objets de fixture et les disposer en tant que variables d'instance dans chaque test au lieu de les construire individuellement pour chaque test.

Vous pouvez créer des ressources comme un descripteur de fichier dans le setUp, puis assurez-vous de les fermer dans tearDown. Si vous écrivez des fichiers temporaires, vous pouvez vous assurer de les supprimer. Si vous ouvrez une connexion à une base de données, vous pouvez la fermer (bien que vous souhaitiez peut-être le faire ailleurs - setupBeforeClass/tearDownAfterClass qui sera appelé pour chaque fichier de test, pas pour chaque cas de test.)

C'est juste un crochet avant/après, ce qui est génial en général. Utilisez-le pour vous rendre la vie plus facile ou ne l'utilisez pas.

4
Koobz

Vous pouvez l'utiliser presque n'importe quand si vous aviez une dépendance dans la classe que vous testez. Un exemple classique de ceci pourrait être une sorte d'objet stockant l'état de l'application (un objet de session, un panier, etc.).

Supposons, par exemple, que ma classe calculait les frais d’expédition sur le contenu d’un panier défini par un objet du panier. Et disons que ce panier est transféré dans la classe de calcul d'expédition via l'injection de dépendance. Pour tester la plupart des méthodes de la classe, vous devrez peut-être instancier un objet panier et le définir dans la classe afin de tester vos différentes méthodes. Vous devrez peut-être aussi ajouter des objets dans le panier. Donc, vous pourriez avoir une configuration comme celle-ci:

public function setUp()
{
    $this->cart = new cart();
    $this->cart->add_item('abc');
    $this->cart->add_item('xyz');
}

Supposons également que vos méthodes de test puissent en réalité modifier les éléments du panier, en les décorant avec les informations de coût d’expédition. Vous ne voulez pas que les informations d’un test saignent dans le suivant, vous devez donc désarmer le panier à la fin.

public function tearDown()
    unset($this->cart);
}
1
Mike Brant

Il existe une fuite de mémoire dans l'exemple fourni dans la réponse acceptée . Vous devriez ajouter tearDown:

protected function tearDown()
{
    $this->_mockedService = null;
}

PHPUnit crée un nouvel objet de scénario de test pour chaque appel de méthode de test. Donc, s'il y a 4 méthodes de test - il y aura 4 objets et 4 mockedService seront créés. Et ils ne seraient pas supprimés jusqu'à la fin du script (suite de tests complète) . Vous devez donc supprimer tous les objets et désélectionner toutes les variables dans tearDown pour éviter les fuites de mémoire.

1
Nick