Gerard Meszaros introduit le concept de doublure de test dans [Meszaros2007] comme ceci:
La méthode getMock($nomClasse)
fournit par PHPUnit peut être
utilisée dans un test pour générer automatiquement un objet qui peut agir comme une
doublure de test pour une classe originelle indiquée. Cette doublure de test peut être
utilisée dans tous les contextes où la classe originelle est attendue.
Par défaut, toutes les méthodes de la classe originelle sont remplacées
par une implémentation fictive qui se contente de retourner
NULL
(sans appeler la méthode originelle).
En utilisant la méthode will($this->returnValue())
par exemple, vous pouvez configurer ces implémentations fictives pour
retourner une valeur donnée quand elles sont appelées.
Merci de noter que les méthodes final
, private
et static
ne peuvent pas être remplacées par un bouchon (stub) ou un simulacre (mock). Elles seront
ignorées par la fonction de doublure de test de PHPUnit et conserveront leur comportement
initial.
La pratique consistant à remplacer un objet par une doublure de test qui retourne (de façon facultative) des valeurs de retour configurées est appelée bouchonnage. Vous pouvez utiliser un bouchon pour "remplacer un composant réel dont dépend le système testé de telle façon que le test possède un point de contrôle sur les entrées indirectes dans le SCT. Ceci permet au test de forcer le SCT à utiliser des chemins qu'il n'aurait pas emprunté autrement".
Exemple 8.2, « Bouchonner un appel de méthode pour retourner une valeur fixée » montre comment
la méthode de bouchonnage appelle et configure des valeurs de retour. Nous utilisons
d'abord la méthode getMock()
qui est fournie par la classe
PHPUnit_Framework_TestCase
pour configurer un objet bouchon
qui ressemble à un objet de UneClasse
(Exemple 8.1, « La classe que nous voulons bouchonner »). Ensuite nous
utilisons l'interface souple
que PHPUnit fournit pour indiquer le comportement de ce bouchon. En essence,
cela signifie que vous n'avez pas besoin de créer plusieurs objets temporaires
et les relier ensemble ensuite. Au lieu de cela, vous chaînez les appels de méthode
comme montré dans l'exemple. Ceci amène à un code plus lisible et "souple".
Exemple 8.1. La classe que nous voulons bouchonner
<?php class UneClasse { public function faireQuelquechose() { // Faire quelque chose. } } ?>
Exemple 8.2. Bouchonner un appel de méthode pour retourner une valeur fixée
<?php require_once 'UneClasse.php'; class BouchonTest extends PHPUnit_Framework_TestCase { public function testBouchon() { // Créer un bouchon pour la classe UneClasse. $bouchon = $this->getMock('UneClasse'); // Configurer le bouchon. $bouchon->expects($this->any()) ->method('faireQuelquechose') ->will($this->returnValue('foo')); // Appeler $bouchon->faireQuelquechose() va maintenant retourner // 'foo'. $this->assertEquals('foo', $bouchon->faireQuelquechose()); } } ?>
"Derrière la scène", PHPUnit génère automatiquement une nouvelle classe qui
implémente le comportement souhaité quand la méthode getMock()
est utilisée. La classe doublure de test peut être configurée via des
paramètres optionnels de la méthode getMock()
.
Par défaut, toutes les méthodes d'une classe données sont remplacées par une doublure de test qui retourne simplement NULL
à moins qu'une valeur de retour ne soit configurée en utilisant will($this->returnValue())
, par exemple.
Quand le deuxième paramètre (facultatif) est fourni, seules les méthodes dont les noms sont dans le tableau sont remplacées par une doublure de test configurable. Le comportement des autres méthodes n'est pas modifié.
Le troisième paramètre (facultatif) peut contenir un tableau de paramètre qui est passé dans le constructeur de la classe originelle (qui n'est pas remplacé par une implémentation fictive par défaut).
Le quatrième paramètre (facultatif) peut être utilisé pour indiquer un nom de classe pour la classe de doublure de test générée.
Le cinquième paramètre (facultatif) peut être utilisée pour désactiver l'appel du constructeur de la classe originelle.
Le sixième paramètre (facultatif) peut être utilisé pour désactiver l'appel au constructeur du clone de la classe originelle.
Le septième paramètre (facultatif) peut être utilisé pour désactiver __autoload()
lors de la génération de la classe de doublure de test.
Alternativement, l'API Mock Builder peut être utilisé pour configurer la classe de doublure de test générée. Exemple 8.3, « Utiliser l'API Mock Builder pour configurer la classe de doublure de test générée. » montre un exemple. Ici, il y a une liste de méthodes qui peuvent être utilisées avec l'interface de Mock Builder:
setMethods(array $methodes)
peut être appelée sur l'objet Mock Builder pour indiquer les méthodes qui doivent être remplacées par une doublure de test configurable. Le comportement des autres méthodes n'est pas modifié.
setConstructorArgs(array $parametres)
peut être appelé pour fournir un paramètre tableau qui est passé au constructeur de la classe originelle (qui n'est pas remplacé par une implémentation fictive par défaut).
setMockClassName($nom)
peut être utilisée pour indiquer un nom de classe pour la classe de doublure de test générée.
disableOriginalConstructor()
peut être utilisé pour désactiver l'appel au constructeur de la classe originelle.
disableOriginalClone()
peut être utilisé pour désactiver l'appel au constructeur clone de la classe originelle.
disableAutoload()
peut être utilisée pour désactiver __autoload()
lors de la génération de la classe de doublure de test.
Exemple 8.3. Utiliser l'API Mock Builder pour configurer la classe de doublure de test générée.
<?php require_once 'UneClasse.php'; class BouchonTest extends PHPUnit_Framework_TestCase { public function testBouchon() { // Créer un bouchon pour la classe UneClasse. $bouchon = $this->getMockBuilder('UneClasse') ->disableOriginalConstructor() ->getMock(); // Configure le bouchon. $bouchon->expects($this->any()) ->method('faireQuelquechose') ->will($this->returnValue('foo')); // Appeler $bouchon->faireQuelquechose() retournera maintenant // 'foo'. $this->assertEquals('foo', $bouchon->faireQuelquechose()); } } ?>
Parfois vous voulez renvoyer l'un des paramètres d'un appel de méthode
(non modifié) comme résultat d'un appel méthode bouchon.
Exemple 8.4, « Bouchonner un appel de méthode pour renvoyer un des paramètres » montre comment vous
pouvez obtenir ceci en utilisant returnArgument()
à la place de
returnValue()
.
Exemple 8.4. Bouchonner un appel de méthode pour renvoyer un des paramètres
<?php require_once 'UneClasse.php'; class BouchonTest extends PHPUnit_Framework_TestCase { public function testReturnArgumentBouchon() { // Créer un bouchon pour la classe UneClasse. $bouchon = $this->getMock('UneClasse'); // Configurer le bouchon. $bouchon->expects($this->any()) ->method('faireQuelquechose') ->will($this->returnArgument(0)); // $bouchon->faireQuelquechose('foo') retourne 'foo' $this->assertEquals('foo', $bouchon->faireQuelquechose('foo')); // $bouchon->faireQuelquechose('bar') retourne 'bar' $this->assertEquals('bar', $bouchon->faireQuelquechose('bar')); } } ?>
Quand on teste interface souple, il est parfois utile que la méthode bouchon
retourne une référence à l'objet bouchon.
Exemple 8.5, « Bouchonner un appel de méthode pour renvoyer une référence de l'objet bouchon. » illustre comment vous
pouvez utiliser returnSelf()
pour accomplir cela.
Exemple 8.5. Bouchonner un appel de méthode pour renvoyer une référence de l'objet bouchon.
<?php require_once 'UneClasse.php'; class BouchonTest extends PHPUnit_Framework_TestCase { public function testReturnSelf() { // Créer un bouchon pour la classe UneClasse. $bouchon = $this->getMock('UneClasse'); // Configurer le bouchon. $bouchon->expects($this->any()) ->method('faireQuelquechose') ->will($this->returnSelf()); // $bouchon->faireQuelquechose() retourne $bouchon $this->assertSame($bouchon, $bouchon->faireQuelquechose()); } } ?>
Parfois, une méthode bouchon doit retourner différentes valeurs selon
une liste prédéfinie d'arguments. Vous pouvez utiliser
returnValueMap()
pour créer un mappage qui associe des
paramètres aux valeurs de retour correspondantes. Voir
Exemple 8.6, « Bouchonner un appel de méthode pour retourner la valeur à partir d'un mappage » pour
un exemple.
Exemple 8.6. Bouchonner un appel de méthode pour retourner la valeur à partir d'un mappage
<?php require_once 'UneClasse.php'; class BouchonTest extends PHPUnit_Framework_TestCase { public function testReturnValueMapBouchon() { // Créer un bouchon pour la classe UneClasse. $bouchon = $this->getMock('UneClasse'); // Créer un mappage des arguments // et des valeurs de retour. $map = array( array('a', 'b', 'c', 'd'), array('e', 'f', 'g', 'h') ); // Configurer le bouchon. $bouchon->expects($this->any()) ->method('faireQuelquechose') ->will($this->returnValueMap($map)); // $bouchon->faireQuelquechose() retourne // différentes valeurs selon les paramètres // fournis. $this->assertEquals('d', $bouchon->faireQuelquechose('a', 'b', 'c')); $this->assertEquals('h', $bouchon->faireQuelquechose('e', 'f', 'g')); } } ?>
Quand l'appel méthode bouchonné doit retourner une valeur calculée au lieu
d'une valeur fixée (voir returnValue()
) ou un paramètre
(non modifié) (voir returnArgument()
), vous pouvez utiliser
returnCallback()
pour que la méthode retourne le résultat
d'une fonction ou méthode de rappel. Voir
Exemple 8.7, « Bouchonner un appel de méthode pour retourner une valeur à partir d'un rappel » pour un exemple.
Exemple 8.7. Bouchonner un appel de méthode pour retourner une valeur à partir d'un rappel
<?php require_once 'UneClasse.php'; class BouchonTest extends PHPUnit_Framework_TestCase { public function testReturnCallbackBouchon() { // Créer un bouchon pour la classe UneClasse. $bouchon = $this->getMock('UneClasse'); // Configurer le bouchon. $bouchon->expects($this->any()) ->method('faireQuelquechose') ->will($this->returnCallback('str_rot13')); // $bouchon->faireQuelquechose($argument) retourne str_rot13($argument) $this->assertEquals('fbzrguvat', $bouchon->faireQuelquechose('quelqueChose')); } } ?>
Une alternative plus simple pour configurer une méthode de rappel peut
consister à indiquer une liste de valeurs désirées. Vous pouvez faire
ceci avec la méthode onConsecutiveCalls()
. Voir
Exemple 8.8, « Bouchonner un appel de méthode pour retourner une liste de valeurs dans l'ordre indiqué » pour
un exemple.
Exemple 8.8. Bouchonner un appel de méthode pour retourner une liste de valeurs dans l'ordre indiqué
<?php require_once 'UneClasse.php'; class BouchonTest extends PHPUnit_Framework_TestCase { public function testOnConsecutiveCallsBouchon() { // Créer un bouchon pour la classe UneClasse. $bouchon = $this->getMock('UneClasse'); // Configurer le bouchon. $bouchon->expects($this->any()) ->method('faireQuelquechose') ->will($this->onConsecutiveCalls(2, 3, 5, 7)); // $bouchon->faireQuelquechose() retourne une valeur différente à chaque fois $this->assertEquals(2, $bouchon->faireQuelquechose()); $this->assertEquals(3, $bouchon->faireQuelquechose()); $this->assertEquals(5, $bouchon->faireQuelquechose()); } } ?>
Au lieu de retourner une valeur, une méthode bouchon peut également lever
une exception. Exemple 8.9, « Bouchonner un appel de méthode pour lever une exception »
montre comme utiliser throwException()
pour faire cela.
Exemple 8.9. Bouchonner un appel de méthode pour lever une exception
<?php require_once 'UneClasse.php'; class BouchonTest extends PHPUnit_Framework_TestCase { public function testThrowExceptionBouchon() { // Créer un bouchon pour la classe UneClasse. $bouchon = $this->getMock('UneClasse'); // Configurer le bouchon. $bouchon->expects($this->any()) ->method('faireQuelquechose') ->will($this->throwException(new Exception)); // $bouchon->faireQuelquechose() lance l'Exception $bouchon->faireQuelquechose(); } } ?>
Alternativement, vous pouvez écrire le bouchon vous-même et améliorer
votre conception ce-faisant. Des ressources largement utilisées sont
accédées via une unique façade, de telle sorte que vous pouvez facilement
remplacer la ressource avec le bouchon. Par exemple, au lieu d'avoir
des appels directs à la base de données éparpillés dans tout le code,
vous avez un unique objet Database
, une implémentation de
l'interface IDatabase
. Ensuite, vous pouvez créer
une implémentation bouchon de IDatabase
et l'utiliser pour
vos tests. Vous pouvez même créer une option pour lancer les tests dans la
base de données bouchon ou la base de données réelle, de telle sorte que vous
pouvez utiliser vos tests à la fois pour tester localement pendant le développement
et en intégration avec la vraie base de données.
Les fonctionnalités qui nécessitent d'être bouchonnées tendent à se regrouper dans le même objet, améliorant la cohésion. En représentant la fonctionnalité avec une unique interface cohérente, vous réduisez le couplage avec le reste du système.
La pratique consistant à remplacer un objet avec une doublure de test qui vérifie des attentes, par exemple en faisant l'assertion qu'une méthode a été appelée, est appelée simulacre.
Vous pouvez utiliser un objet simulacre "comme un point d'observation qui est utilisé pour vérifier les sorties indirectes du système quand il est testé. Typiquement, le simulacre inclut également la fonctionnalité d'un bouchon de test, en ce sens qu'il doit retourner les valeurs du système testé s'il n'a pas déjà fait échouer les tests mais l'accent est mis sur la vérification des sorties indirectes. Ainsi, un simulacre est un beaucoup plus qu'un simple bouchon avec des assertions; il est utilisé d'une manière fondamentalement différente".
Voici un exemple: supposons que vous voulez tester que la méthode correcte,
update()
dans notre exemple, est appelée d'un objet qui observe un autre objet.
Exemple 8.10, « Les classes Sujet et Observateur qui sont une partie du système testé »
illustre le code pour les classes Sujet
et Observateur
qui sont une partie du système testé (SUT).
Exemple 8.10. Les classes Sujet et Observateur qui sont une partie du système testé
<?php class Sujet { protected $observateurs = array(); public function attache(Observateur $observateur) { $this->observateurs[] = $observateur; } public function faireQuelquechose() { // Faire quelque chose. // ... // Avertir les observateurs que nous faisons quelque chose. $this->notify('quelque chose'); } public function faireQuelquechoseMal() { foreach ($this->observateurs as $observateur) { $observateur->reportError(42, 'Quelque chose de mal est arrivé', $this); } } protected function notify($paramètre) { foreach ($this->observateurs as $observateur) { $observateur->update($paramètre); } } // Autres méthodes. } class Observateur { public function update($paramètre) { // Faire quelque chose. } public function reportError($codeErreur, $messageErreur, Sujet $sujet) { // Faire quelque chose } // Autres méthodes. } ?>
Exemple 8.11, « Tester qu'une méthode est appelée une fois et avec un paramètre indiqué »
illustre comment utiliser un simulacre pour tester l'interaction entre
les objets Sujet
et Observateur
.
Nous utilisons d'abord la méthode getMock()
qui est fournie par
la classe PHPUnit_Framework_TestCase
pour configurer un simulacre
pour l'Observateur
. Puisque nous donnons un tableau comme second
paramètre (facultatif) pour la méthode getMock()
,
seule la méthode update()
de la classe Observateur
est
remplacée par une implémentation d'un simulacre.
Exemple 8.11. Tester qu'une méthode est appelée une fois et avec un paramètre indiqué
<?php require_once 'Sujet.php'; class SujetTest extends PHPUnit_Framework_TestCase { public function testLesObservateursSontMisAJour() { // Créer un simulacre pour la classe Observateur, // ne touchant que la méthode update(). $observateur = $this->getMock('Observateur', array('update')); // Configurer l'attente de la méthode update() // d'être appelée une seule fois et avec la chaîne 'quelquechose' // comme paramètre. $observateur->expects($this->once()) ->method('update') ->with($this->equalTo('quelque chose')); // Créer un objet Sujet et y attacher l'objet Observateur // simulé $sujet = new Sujet; $sujet->attache($observateur); // Appeler la méthode faireQuelquechose() sur l'objet $sujet // que nous attendons voir appeler la méthode update() de l'objet // simulé Observateur avec la chaîne 'quelqueChose'. $sujet->faireQuelquechose(); } } ?>
La méthode with()
peut prendre n'importe quel
nombre de paramètres, correspondant au nombre de paramètres des méthodes
étant simulées. Vous pouvez indiquer des contraintes plus avancées
sur les paramètres de méthode qu'une simple correspondance.
Exemple 8.12. Tester qu'une méthode est appelée avec un nombre de paramètres contraints de différentes manières
<?php class SubjectTest extends PHPUnit_Framework_TestCase { public function testRapportErreur() { // Créer un simulacre pour la classe Observateur, en simulant // la méthode rapportErreur() $observateur = $this->getMock('Observateur', array('rapportErreur')); $observateur->expects($this->once()) ->method('rapportErreur') ->with($this->greaterThan(0), $this->stringContains('Quelquechose'), $this->anything()); $sujet = new Subject; $sujet->attach($observateur); // La méthode faireQuelquechoseDeMal doit rapporter une erreur à l'observateur // via la méthode rapportErreur() $sujet->faireQuelquechoseDeMal(); } } ?>
Tableau 2.3, « Contraintes » montre les contraintes qui peuvent être appliquées aux paramètres de méthode et Tableau 8.1, « Matchers » montre les matchers qui sont disponibles pour indiquer le nombre d' invocations.
Tableau 8.1. Matchers
Matcher | Signification |
---|---|
PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount any() | Retourne un matcher qui correspond quand la méthode pour laquelle il est évalué est exécutée zéro ou davantage de fois. |
PHPUnit_Framework_MockObject_Matcher_InvokedCount never() | Retourne un matcher qui correspond quand la méthode pour laquelle il est évalué n'est jamais exécutée. |
PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce atLeastOnce() | Retourne un matcher qui correspond quand la méthode pour laquelle il est évalué est exécutée au moins une fois. |
PHPUnit_Framework_MockObject_Matcher_InvokedCount once() | Retourne un matcher qui correspond quand la méthode pour laquelle il est évalué est exécutée exactement une fois. |
PHPUnit_Framework_MockObject_Matcher_InvokedCount exactly(int $nombre) | Retourne un matcher qui correspond quand la méthode pour laquelle il est évalué est exécutée exactement $nombre fois. |
PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex at(int $index) | Retourne un matcher qui correspond quand la méthode pour laquelle il est évalué est invoquée pour l'$index spécifié. |
La méthode getMockForAbstractClass()
retourne un simulacre
pour une classe abstraite. Toutes les méthodes abstraites d'une classe simulacre
donnée sont simulées. Ceci permet de tester les méthodes concrètes d'une classe
abstraite.
Exemple 8.13. Tester les méthodes concrêtes d'une classe abstraite
<?php abstract class ClasseAbstraite { public function methodeConcrete() { return $this->methodeAbstraite(); } public abstract function methodeAbstraite(); } class ClasseAbstraiteTest extends PHPUnit_Framework_TestCase { public function testConcreteMethod() { $stub = $this->getMockForAbstractClass('ClasseAbstraite'); $stub->expects($this->any()) ->method('methodeAbstraite') ->will($this->returnValue(TRUE)); $this->assertTrue($stub->methodeConcrete()); } } ?>
Quand votre application interagit avec un web service, vous voulez le
tester sans vraiment interagir avec le web service. Pour rendre facile
la création de bouchon ou de simulacre de web services,
getMockFromWsdl()
peut être utilisée de la même façon que
getMock()
(voir plus haut). La seule différence est que
getMockFromWsdl()
retourne un bouchon ou un simulacre
basé sur la description en WSDL d'un web service tandis que getMock()
retourne un bouchon ou un simulacre basé sur une classe ou une interface PHP.
Exemple 8.14, « Bouchonner un web service »
montre comment getMockFromWsdl()
peut être utilisé pour faire un bouchon,
par exemple, d'un web service décrit dans GoogleSearch.wsdl
.
Exemple 8.14. Bouchonner un web service
<?php class GoogleTest extends PHPUnit_Framework_TestCase { public function testSearch() { $googleSearch = $this->getMockFromWsdl( 'GoogleSearch.wsdl', 'GoogleSearch' ); $directoryCategory = new StdClass; $directoryCategory->fullViewableName = ''; $directoryCategory->specialEncoding = ''; $element = new StdClass; $element->summary = ''; $element->URL = 'http://www.phpunit.de/'; $element->snippet = '...'; $element->title = '<b>PHPUnit</b>'; $element->cachedSize = '11k'; $element->relatedInformationPresent = TRUE; $element->hostName = 'www.phpunit.de'; $element->directoryCategory = $directoryCategory; $element->directoryTitle = ''; $result = new StdClass; $result->documentFiltering = FALSE; $result->searchComments = ''; $result->estimatedTotalResultsCount = 3.9000; $result->estimateIsExact = FALSE; $result->resultElements = array($element); $result->searchQuery = 'PHPUnit'; $result->startIndex = 1; $result->endIndex = 1; $result->searchTips = ''; $result->directoryCategories = array(); $result->searchTime = 0.248822; $googleSearch->expects($this->any()) ->method('doGoogleSearch') ->will($this->returnValue($result)); /** * $googleSearch->doGoogleSearch() va maintenant retourner un result bouchon et * la méthode doGoogleSearch() du web service ne sera pas invoquée. */ $this->assertEquals( $result, $googleSearch->doGoogleSearch( '00000000000000000000000000000000', 'PHPUnit', 0, 1, FALSE, '', FALSE, '', '', '' ) ); } } ?>
vfsStream est un encapsuleur de flux pour un système de fichiers virtuel qui peut s'avérer utile dans des tests unitaires pour simuler le vrai système de fichiers.
Pour installer vfsStream, le canal PEAR
(pear.bovigo.org
) qui est utilisé pour
sa distribution doit être enregistré dans l'environnement local PEAR:
pear channel-discover pear.bovigo.org
Ceci ne doit être fait qu'une seule fois. Maintenant, l'installeur PEAR peut être utilisé pour installer vfsStream.
pear install bovigo/vfsStream-beta
Exemple 8.15, « Une classe qui interagit avec le système de fichiers » montre une classe qui interagit avec le système de fichiers.
Exemple 8.15. Une classe qui interagit avec le système de fichiers
<?php class Exemple { protected $id; protected $repertoire; public function __construct($id) { $this->id = $id; } public function setRepertoire($repertoire) { $this->repertoire = $repertoire . DIRECTORY_SEPARATOR . $this->id; if (!file_exists($this->repertoire)) { mkdir($this->repertoire, 0700, TRUE); } } }?>
Sans un système de fichiers virtuel tel que vfsStream, nous ne pouvons
pas tester la méthode setDirectory()
en isolation des influences
extérieures (voir Exemple 8.16, « Tester une classe qui interagoit avec le système de fichiers »).
Exemple 8.16. Tester une classe qui interagoit avec le système de fichiers
<?php require_once 'Exemple.php'; class ExempleTest extends PHPUnit_Framework_TestCase { protected function setUp() { if (file_exists(dirname(__FILE__) . '/id')) { rmdir(dirname(__FILE__) . '/id'); } } public function testReprtoireEstCree() { $example = new Exemple('id'); $this->assertFalse(file_exists(dirname(__FILE__) . '/id')); $example->setRepertoire(dirname(__FILE__)); $this->assertTrue(file_exists(dirname(__FILE__) . '/id')); } protected function tearDown() { if (file_exists(dirname(__FILE__) . '/id')) { rmdir(dirname(__FILE__) . '/id'); } } } ?>
L'approche précédente possède plusieurs inconvénients :
Comme avec les ressources externes, il peut y a voir des problèmes intermittents avec le système de fichiers. Ceci rend les tests qui interagissent avec lui peu fiables.
Dans les méthodes setUp()
et tearDown()
, nous avons à nous assurer que le répertoire n'existe pas avant et après le test.
Si l'exécution du test s'achève avant que la méthode tearDown()
n'ait été appelée, le répertoire va rester dans le système de fichiers.
Exemple 8.17, « Simuler le système de fichiers dans un test pour une classe qui interagit avec le système de fichiers » montre comment vfsStream peut être utilisé pour simuler le système de fichiers dans un test pour une classe qui interagit avec le système de fichiers.
Exemple 8.17. Simuler le système de fichiers dans un test pour une classe qui interagit avec le système de fichiers
<?php require_once 'vfsStream/vfsStream.php'; require_once 'Exemple.php'; class ExempleTest extends PHPUnit_Framework_TestCase { public function setUp() { vfsStreamWrapper::register(); vfsStreamWrapper::setRoot(new vfsStreamDirectory('exempleRepertoire')); } public function testRepertoireEstCree() { $exemple = new Exemple('id'); $this->assertFalse(vfsStreamWrapper::getRoot()->hasChild('id')); $exemple->setRepertoire(vfsStream::url('exempleRepertoire')); $this->assertTrue(vfsStreamWrapper::getRoot()->hasChild('id')); } } ?>
Ceci présente plusieurs avantages :
Le test lui-même est plus concis.
vfsStream donne au développeur du test le plein contrôle sur la façon dont le code testé voit l'environnement du système de fichiers.
Puisque les opérations du système de fichiers n'opèrent plus sur le système de fichiers réel, les opérations de nettoyage dans la méthode tearDown()
ne sont plus nécessaires.