19

Click here to load reader

Mocks Arent Stubs

Embed Size (px)

DESCRIPTION

Mocks Arent Stubs

Citation preview

  • Tests unitaires et doublures de tests : lessimulacres ne sont pas des bouchons

    Par Martin Fowler - Bruno Orsier

    Date de publication : 31 aot 2007

    Dernire mise jour : 29 octobre 2007

    Le terme "objet simulacre" est devenu populaire pour dcrire des objets spciaux quiimitent de vrais objets dans le but de les tester. La plupart des environnements dedveloppement ont maintenant des outils qui permettent de crer facilement des objetssimulacres. Cependant, souvent on ne ralise pas que les objets simulacres sont un casparticulier d'objets de tests, qui permettent un style de test diffrent. Dans cet articlej'explique comment les objets simulacres fonctionnent, comment ils encouragent le testbas sur la vrification du comportement, et comment la communaut autour d'eux lesutilise pour dvelopper un style de test diffrent.

    Dernire mise jour significative : 02 Janvier 2007

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 2 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Notes du traducteur..................................................................................................................................................... 3Remerciements....................................................................................................................................................... 3

    Introduction...................................................................................................................................................................4Les tests traditionnels.................................................................................................................................................. 5Les tests avec des objets simulacres......................................................................................................................... 7

    Utilisation de EasyMock......................................................................................................................................... 8La diffrence entre les simulacres et les bouchons..................................................................................................10Les styles de test classique et orient-simulacre..................................................................................................... 12Comment choisir parmi les diffrences ?.................................................................................................................. 13

    Le guidage du TDD..............................................................................................................................................13L'initialisation des classes de test........................................................................................................................14L'isolation des tests.............................................................................................................................................. 14Le couplage des tests avec les implmentations................................................................................................ 15Le style de conception......................................................................................................................................... 16

    Faut-il tre un testeur classique ou orient-simulacres ?......................................................................................... 17Considrations finales................................................................................................................................................18Lectures complmentaires......................................................................................................................................... 19

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 3 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Notes du traducteur

    Le papier original en anglais est disponible ici.

    Les exemples de cet article sont en Java, mais je les ai convertis en C#, (en utilisant par exemple NMock2,TypeMock) afin de rendre cet article plus facilement accessible la communaut .NET.

    Le vocabulaire anglais employ dans la littrature de test est assez dlicat traduire en franais (et je suis d'ailleurssoulag que Martin Fowler souligne que mme en anglais ce vocabulaire est assez confus). J'ai suivi les traductionsproposes ici. Donc la traduction utilise la table de correspondance ci-dessous :

    mot anglais mot franaismock simulacrefake substitutstub bouchondummy fantme

    Il y a plusieurs alternatives : objets fantaisie, mimes, etc.

    Le mot stub est particulirement vide de sens pour un francophone... Cette discussion au sujet de la traduction deto stub out est assez rvlatrice.

    En ce qui concerne la traduction de l'acronyme TDD (pour Test Driven Development), l'quivalent franais DDT(Dveloppement Dirig par les Tests) n'est pas trs parlant, ni trs courant. Par consquent TDD n'a pas t traduit.De mme pour BDD (Behavior Driven Development) dont l'quivalent franais serait DDC (Dveloppement Dirigpar le Comportement). BDD n'a pas t traduit non plus.

    Remerciements

    Merci Miles, Ricky81, UNi[FR], RideKick pour leurs relectures de cette traduction, et Alp pour sa relecture desexemples en C#.

    Merci galement Ditch et Giovanny Temgoua pour leurs diverses suggestions qui ont permis d'amliorer cet article.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 4 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Introduction

    J'ai rencontr pour la premire fois le terme "objet simulacre" dans la communaut XP il y a quelques annes. Depuisje les ai rencontrs de plus en plus. D'une part parce ce que beaucoup des principaux dveloppeurs de ces objetsont fait partie de mes collgues ThoughtWorks diffrents moments. D'autre part parce que je les vois de plus enplus dans la littrature sur les tests influence par XP.

    Mais trop souvent je vois que les objets simulacres sont mal dcrits. En particulier je les vois souvent confondus avecles bouchons - des utilitaires souvent employs dans les environnements de tests. Je comprends cette confusion - jeles ai considrs comme similaires pendant un moment, mais des conversations avec les dveloppeurs de simulacresont fait rgulirement pntrer un peu de comprhension des simulacres dans mon crne de tortue.

    Cette diffrence est en fait compose de deux diffrences distinctes. D'une part il y a une diffrence dans la vrificationdes tests : il faut distinguer vrification d'tat et vrification de comportement. D'autre part il y a une diffrence dephilosophie dans la manire dont le test et la conception interagissent, ce que je nomme ici par style "classique" et"orient-simulacre" du dveloppement dirig par les tests.

    (Dans la version prcdente de cet essai, j'avais ralis qu'il y avait une diffrence, mais je combinais les deuxensemble. Depuis, ma comprhension s'est amliore et il est temps de mettre jour cet essai. Si vous n'avez paslu le prcdent essai vous pouvez ignorer mes douleurs croissantes, car j'ai crit cet essai comme si la prcdenteversion n'existait pas. Mais si vous tes familier avec la prcdente version, vous pourriez trouver utile de noter quej'ai cass la vieille dichotomie des tests bass sur l'tat / tests bass sur l'interaction en deux dichotomies : celle dela vrification tat/comportement et celle du style classique/orient-simulacre. J'ai galement ajust mon vocabulairepour qu'il corresponde celui du livre de Gerard Meszaros xUnit Test Patterns).

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 5 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Les tests traditionnels

    Je vais commencer par illustrer les deux styles avec un exemple simple (l'exemple est en Java, mais les principessont valables pour n'importe quel langage orient-objet). Nous voulons prendre un objet Commande (Order) et leremplir partir d'un objet Entrept (Warehouse). La commande est trs simple, avec un seul produit et une quantit.L'entrept contient les inventaires de diffrents produits. Quand nous demandons une commande de se remplirelle-mme partir d'un entrept, il y a deux rponses possibles. S'il y a suffisamment de produit dans l'entrept poursatisfaire la commande, la commande est considre remplie, et dans l'entrept la quantit de produit est rduite dumontant appropri. S'il n'y a pas suffisamment de produit alors la commande n'est pas remplie, et rien ne se produitau niveau de l'entrept.

    Ces deux comportements impliquent quelques tests, qui sont des tests JUnit assez conventionnels :

    public class OrderStateTester extends TestCase { private static String TALISKER = "Talisker"; private static String HIGHLAND_PARK = "Highland Park"; private Warehouse warehouse = new WarehouseImpl();

    protected void setUp() throws Exception { warehouse.add(TALISKER, 50); warehouse.add(HIGHLAND_PARK, 25); } public void testOrderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50); order.fill(warehouse); assertTrue(order.isFilled()); assertEquals(0, warehouse.getInventory(TALISKER)); } public void testOrderDoesNotRemoveIfNotEnough() { Order order = new Order(TALISKER, 51); order.fill(warehouse); assertFalse(order.isFilled()); assertEquals(50, warehouse.getInventory(TALISKER)); }

    Note du traducteur : cet exemple est disponible en C# ici.

    Les tests xUnit suivent une squence typique de quatre phases : initialisation, excution, vrification, nettoyage. Dansce cas la phase d'initialisation est faite partiellement dans la mthode setUp (initialiser l'entrept) et partiellementdans la mthode de test (initialisation de la commande). L'appel order.fill est la phase d'excution. C'est l quel'objet est incit faire la chose que nous voulons tester. Les dclarations assert sont ensuite la phase de vrification,elles contrlent si la mthode excute a fait correctement son travail. Dans ce cas il n'y a pas de phase de nettoyageexplicite, car le ramasse-miettes le fait implicitement pour nous.

    Durant l'initialisation il y a deux sortes d'objets que nous mettons ensemble. Order est la classe que nous testons,mais pour que order.fill fonctionne, nous avons galement besoin d'une instance de Warehouse. Dans cette situationOrder est l'objet sur lequel nous focalisons le test. Les gens orients-tests aiment utiliser des termes comme l'"objeten cours de test" ou le "systme en cours de test" pour nommer une telle chose. Chacun de ces termes est difficile dire, mais comme ils sont largement accepts je me force les utiliser. Suivant Meszaros j'utilise Systme en coursde test, ou encore l'abrviation SCT.

    Donc pour ce test j'ai besoin du SCT (Order) et d'un collaborateur (Warehouse). J'ai besoin de Warehouse pourdeux raisons : d'une part pour faire fonctionner le comportement test (puisque order.fill appelle les mthodes dewarehouse) et d'autre part pour la vrification (puisqu'un des rsultats de order.fill est un changement potentiel dansl'tat de Warehouse). Au fur et au mesure que nous allons explorer ce sujet, vous allez voir que nous insisteronsbeaucoup sur la distinction entre le SCT et les collaborateurs (dans la version plus ancienne de cet article je parlaisdu SCT comme l'"objet primaire" et des collaborateurs comme les "objets secondaires").

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 6 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Ce type de test utilise la vrification de l'tat, ce qui signifie que nous dterminons si la mthode excute afonctionn correctement en examinant l'tat du SCT et de ses collaborateurs aprs l'excution de la mthode. Commenous le verrons, les objets simulacres permettent une approche diffrente de la vrification.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 7 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Les tests avec des objets simulacres

    Maintenant je prends exactement le mme comportement mais j'utilise des objets simulacres. Pour ce code j'utilisela bibliothque jMock pour dfinir les simulacres. jMock est une bibliothque java pour les objets simulacres. Il y ad'autres bibliothques pour objets simulacres, mais celle-ci est jour et est dveloppe par les crateurs de cettetechnique, donc c'est un bon point de dpart.

    public class OrderInteractionTester extends MockObjectTestCase { private static String TALISKER = "Talisker";

    public void testFillingRemovesInventoryIfInStock() { //setup - data Order order = new Order(TALISKER, 50); Mock warehouseMock = new Mock(Warehouse.class); //setup - expectations warehouseMock.expects(once()).method("hasInventory") .with(eq(TALISKER),eq(50)) .will(returnValue(true)); warehouseMock.expects(once()).method("remove") .with(eq(TALISKER), eq(50)) .after("hasInventory");

    //exercise order.fill((Warehouse) warehouseMock.proxy()); //verify warehouseMock.verify(); assertTrue(order.isFilled()); }

    public void testFillingDoesNotRemoveIfNotEnoughInStock() { Order order = new Order(TALISKER, 51); Mock warehouse = mock(Warehouse.class); warehouse.expects(once()).method("hasInventory") .withAnyArguments() .will(returnValue(false));

    order.fill((Warehouse) warehouse.proxy());

    assertFalse(order.isFilled()); }

    Note du traducteur : cet exemple est disponible en C# ici.

    Concentrez vous d'abord sur le test testFillingRemovesInventoryIfInStock , car j'ai pris quelques raccourcis avecl'autre test.

    Tout d'abord, la phase d'initialisation est trs diffrente. Pour commencer, elle est divise en deux parties : lesdonnes et les attentes. La partie donnes initialise les objets qui nous intressent, et en ce sens elle est similaire l'initialisation traditionnelle. La diffrence rside dans les objets qui sont crs. le SCT est le mme - une commande.Cependant le collaborateur n'est plus un entrept, mais un simulacre d'entrept - techniquement une instance dela classe Mock.

    La deuxime partie de l'initialisation cre des attentes sur l'objet simulacre. Les attentes indiquent quelles mthodesdevraient tre appeles sur les simulacres quand le SCT est excut.

    Une fois que les attentes sont en place, j'excute le SCT. Aprs l'excution je fais alors la vrification, qui a deuxaspects. J'utilise des assertions sur le SCT - peu prs comme avant. Cependant je vrifie galement les simulacres- en contrlant qu'ils ont bien t appels selon leurs attentes.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 8 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    La diffrence cl ici est comment nous vrifions que la commande a fait ce qu'elle devait dans son interaction avecl'entrept. Avec la vrification d'tat, nous faisons cela avec des assertions sur l'tat de l'entrept. Les simulacresutilisent la vrification du comportement, et nous vrifions alors si la commande a fait les bons appels de mthodessur l'entrept. Nous faisons cela pendant l'initialisation en disant au simulacre ce qu'il doit attendre, puis en demandantau simulacre de se vrifier lui-mme durant la phase de vrification. Seule la commande est vrifie l'aided'assertions, et si la mthode teste ne change pas l'tat de la commande, alors il n'y a mme pas d'assertions du tout.

    Dans le deuxime test je fais plusieurs choses diffremment. Premirement je cre le simulacre d'une autre manire,en utilisant la mthode mock dans MockObjectTestCase au lieu du constructeur. C'est une mthode utilitaire de labibliothque jMock, qui me permet d'viter de faire explicitement la vrification plus tard ; en effet tout simulacre creavec cette utilitaire est automatiquement vrifi la fin du test. J'aurais pu faire cela avec le premier test aussi, maisje voulais montrer la vrification d'une manire plus explicite pour bien montrer comment fonctionne le test avec dessimulacres.

    Deuximement, dans le second test, j'ai relch les contraintes sur l'attente en utilisant withAnyArguments. La raisonest que le premier test vrifie dj que le nombre est bien pass l'entrept, aussi le deuxime test n'a pas besoinde rpter cet lment de test. Si la logique de la commande doit tre modifie plus tard, alors un seul test chouera,ce qui facilitera l'effort de migration des tests. J'aurais galement pu laisser entirement de ct withAnyArguments,car c'est le fonctionnement par dfaut.

    Utilisation de EasyMock

    Il y a un certain nombre de bibliothques d'objets simulacres. Je rencontre assez frquemment EasyMock, la foisdans ses versions java et .NET. EasyMock permet galement la vrification du comportement, mais a plusieursdiffrences de style avec jMock qui mritent d'tre discutes. Voici nouveau nos tests :

    public class OrderEasyTester extends TestCase { private static String TALISKER = "Talisker"; private MockControl warehouseControl; private Warehouse warehouseMock; public void setUp() { warehouseControl = MockControl.createControl(Warehouse.class); warehouseMock = (Warehouse) warehouseControl.getMock(); }

    public void testFillingRemovesInventoryIfInStock() { //setup - data Order order = new Order(TALISKER, 50); //setup - expectations warehouseMock.hasInventory(TALISKER, 50); warehouseControl.setReturnValue(true); warehouseMock.remove(TALISKER, 50); warehouseControl.replay();

    //exercise order.fill(warehouseMock); //verify warehouseControl.verify(); assertTrue(order.isFilled()); }

    public void testFillingDoesNotRemoveIfNotEnoughInStock() { Order order = new Order(TALISKER, 51);

    warehouseMock.hasInventory(TALISKER, 51); warehouseControl.setReturnValue(false); warehouseControl.replay();

    order.fill((Warehouse) warehouseMock);

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 9 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    assertFalse(order.isFilled()); warehouseControl.verify(); }}

    Note du traducteur : cet exemple est disponible en C# ici.

    EasyMock utilise la mtaphore enregistrer/rejouer pour dfinir les attentes. Pour chaque objet collaborateur pourlequel vous dsirez un simulacre, vous crez un objet de contrle et un simulacre. Le simulacre implmente l'interfacede l'objet collaborateur, tandis que l'objet de contrle vous donne des fonctionnalits supplmentaires. Pour indiquerune attente, vous appelez la mthode sur le simulacre, avec les arguments que vous attendez. Vous faites ensuiteun appel au contrle si vous voulez une valeur de retour. Une fois que vous avez fini de dfinir les attentes, vousappelez replay sur le contrle - ce stade le simulacre termine l'enregistrement et est prt rpondre au SCT. Unefois que c'est fait vous appelez verify sur le contrle.

    Il semble que les gens sont souvent troubls la premire vue de la mtaphore enregistrer/rejouer, mais qu'ils s'yhabituent rapidement. Elle a un avantage par rapport aux contraintes de jMock en ce que vous faites de vrais appelsde mthodes sur le simulacre au lieu de spcifier des noms de mthodes dans des chanes. Ce qui veut dire quevous pouvez utiliser la compltion de code de votre environnement de dveloppement, et que tout remaniement denoms de mthodes mettra automatiquement jour les tests. L'inconvnient est que vous ne pouvez pas relcherles contraintes.

    Les dveloppeurs de jMock travaillent sur une nouvelle version qui permettra d'utiliser de vrais appels de mthodes.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 10 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    La diffrence entre les simulacres et les bouchons

    Quand ils ont t introduits pour la premire fois, beaucoup de gens ont facilement confondu les objets simulacresavec la notion courante de test avec des bouchons. Depuis ils semblent que les diffrences sont mieux comprises (etj'espre que la prcdente version de cet article y a contribu). Cependant, pour comprendre compltement commentles simulacres sont utiliss, il est important de comprendre la fois les simulacres et les autres types de doubluresde tests ("doublures" ? Ne vous inquitez pas si c'est un nouveau terme pour vous, attendez quelques paragrapheset tout deviendra clair).

    Quand vous testez, vous vous focalisez sur un seul lment du logiciel la fois - d'o le terme courant de test unitaire.Le problme est que pour faire fonctionner un lment particulier, vous avez souvent besoin d'autres lments - parexemple dans notre exemple nous avons besoin de Warehouse.

    Dans les deux types de tests que j'ai montr ci-dessus, le premier type utilise un vrai objet Warehouse, et le deuximeutilise un simulacre de Warehouse, lequel bien sr n'est pas un vrai objet Warehouse. Utiliser un simulacre est doncun moyen de ne pas utiliser un vrai Warehouse dans le test, mais d'autres formes de "faux" objets sont galementutilises.

    Le vocabulaire pour parler de ces notions devient vite confus - toutes sortes de mots sont utiliss : bouchon, simulacre,substitut, fantme. Pour cet article je vais suivre le vocabulaire du livre de Gerard Meszaros. Il n'est pas utilis partout le monde, mais je pense que c'est un bon vocabulaire, et comme il s'agit de mon article j'ai le privilge de choisirquels mots utiliser.

    Meszaros utilise le terme Doublure de Test comme terme gnrique pour tout objet utilis la place d'un vrai objetdans le but de tester. Ce terme correspond au cascadeur qui double un acteur dans un film (un des buts de Meszarostait d'viter tout nom dj largement utilis). Meszaros dfinit alors quatre types particuliers de doublures:

    Fantmes : des objets que l'on fait circuler, mais qui ne sont jamais rellement utiliss. Habituellement ilsservent juste remplir des listes de paramtres.

    Substituts : des objets qui ont de vritables implmentations qui fonctionnent, mais qui gnralementprennent des raccourcis qui les rendent impropre l'utilisation en production (un bon exemple est une basede donnes en mmoire au lieu d'une vraie base de donnes).

    Bouchons : ces objets fournissent des rponses prdfinies des appels faits durant le test, maisgnralement ne rpondent rien d'autre en dehors de ce qui leur a t programm pour le test. Lesbouchons peuvent aussi enregistrer de l'information concernant les appels, par exemple un bouchon depasserelle de courriels peut mmoriser les messages qu'il a "envoy", ou encore seulement le nombre demessages qu'il a "envoys".

    Simulacres : les objets dont nous parlons ici: des objets prprogramms avec des attentes, lesquellesconstituent une spcification des appels qu'ils s'attendent recevoir.

    Parmi toutes ces doublures, seuls les simulacres insistent sur la vrification du comportement. Les autres doublurespeuvent (et gnralement le font) utiliser la vrification d'tat. En fait les simulacres se comportement vraiment commeles autres doublures dans la phase d'excution, car ils ont besoin de faire croire au SCT qu'il parle ses vraiscollaborateurs - mais les simulacres diffrent dans les phases d'initialisation et de vrification.

    Pour explorer un peu plus les doublures de test, nous devons tendre notre exemple. Beaucoup de gens utilisent unedoublure uniquement si le vrai objet est peu pratique manipuler. Ici, disons que nous voulons envoyer un courrielsi un Order choue. Le problme est que nous ne pouvons pas envoyer de vrais courriels des clients pendantnos tests. Donc la place nous crons une doublure de notre systme de courriels, que nous pouvons contrleret manipuler.

    Nous pouvons alors commencer voir la diffrence entre les simulacres et les bouchons. Pour tester cecomportement d'envoi de courriels, nous pourrions crire un simple bouchon comme ceci :

    public interface MailService {

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 11 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    public void send (Message msg);}

    public class MailServiceStub implements MailService { private List messages = new ArrayList(); public void send (Message msg) { messages.add(msg); } public int numberSent() { return messages.size(); }}

    Nous pouvons alors utiliser la vrification d'tat sur le bouchon comme suit :

    class OrderStateTester... public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); MailServiceStub mailer = new MailServiceStub(); order.setMailer(mailer); order.fill(warehouse); assertEquals(1, mailer.numberSent()); }

    Bien sr c'est un test trs simple - il vrifie seulement qu'un message a t envoy. Nous n'avons pas test qu'il at envoy la bonne personne, ni qu'il avait le bon contenu, mais il suffira illustrer mon propos.

    En utilisant des simulacres, ce test serait bien diffrent :

    class OrderInteractionTester... public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); Mock warehouse = mock(Warehouse.class); Mock mailer = mock(MailService.class); order.setMailer((MailService) mailer.proxy());

    mailer.expects(once()).method("send"); warehouse.expects(once()).method("hasInventory") .withAnyArguments() .will(returnValue(false));

    order.fill((Warehouse) warehouse.proxy()); }}

    Dans les deux cas j'utilise une doublure de test la place du vrai service de courriel. La diffrence est dans le faitque le bouchon utilise la vrification d'tat alors que le simulacre utilise la vrification du comportement.

    Pour utiliser la vrification d'tat sur le bouchon, j'ai besoin de quelques mthodes supplmentaires sur le bouchonpour faciliter la vrification. Par consquent le bouchon implmente MailService mais ajoute des mthodes de testsupplmentaires.

    Les simulacres utilisent toujours la vrification du comportement, tandis qu'un bouchon peut faire les deux. Meszarosnomme les bouchons qui utilisent la vrification de comportement comme des Espions de Test. La diffrence rsidedans la manire dont la doublure effectue excution et vrification, et je vous laisse le soin d'explorer cela vous-mme.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 12 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Les styles de test classique et orient-simulacre

    Maintenant j'en suis au point o je peux explorer la deuxime dichotomie entre le test classique et orient-simulacre.Le point principal est quand utiliser un simulacre (ou une autre doublure).

    Le style classique de TDD consiste utiliser de vrais objets si possibles, et une doublure quand le vrai objet esttrop compliqu utiliser. Ainsi un adepte du TDD classique utiliserait le vrai Warehouse et un double pour le servicede courriels. Le type exact de doublure ne compte pas tant que cela.

    Un adepte du style orient-simulacre, par contre, utilisera toujours un simulacre pour tout objet ayant uncomportement intressant, et donc dans ce cas pour la la fois Warehouse et le service de courriels.

    Bien que les diffrents outils de cration de simulacres aient t conus avec le style orient-simulacre en tte,beaucoup d'adeptes du style classique les trouvent utiles pour crer des doubles.

    Une consquence importante du style orient-simulacre est le Dveloppement Dirig par le Comportement (BDD).Le BDD a t initialement dvelopp par mon collgue Dan North comme une technique pour aider les gens mieuxapprendre le Dveloppement Dirig par les Tests en insistant sur la technique de conception que reprsente le TDD.Cela a conduit renommer les tests en comportements pour mieux explorer comment le TDD aide rflchir cequ'un objet doit faire. Le BDD suit une approche oriente-simulacre, mais il va plus loin, la fois dans ses stylesde nommage, et dans son dsir d'intgrer la conception dans sa technique. Je ne vais pas plus loin ici, car le seullien avec cet article est que le BDD est une autre variation du TDD qui tend utiliser les simulacres. Je vous laissesuivre le lien pour plus d'informations.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 13 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Comment choisir parmi les diffrences ?

    Dans cet article j'ai expliqu deux diffrences : vrification de l'tat ou du comportement, style classique ou orientsimulacre. Quels sont les arguments garder l'esprit quand on fait un choix entre ces styles ? Je vais commencerpar le choix entre la vrification de l'tat ou du comportement.

    La premire chose considrer est le contexte. Pensons-nous une collaboration facile, comme entre Order etWarehouse, ou une complique, comme entre Order et le service de courriels ?

    Si c'est une collaboration facile alors le choix est simple. Si je suis un adepte du style classique, je n'utilise pas desimulacre, bouchon ou autre sorte de doublure. J'utilise le vrai objet et la vrification d'tat. Si je suis un adepte dustyle orient-simulacre, j'utilise un simulacre et la vrification du comportement. Pas de dcision prendre du tout.

    Si c'est une collaboration complique, il n'y a pas de dcision si je suis un adepte des simulacres - j'utilise juste dessimulacres et la vrification du comportement. Si je suis un adepte du style classique, alors j'ai le choix, mais il n'estpas bien important. Habituellement les adeptes du style classique dcident au cas par cas, en utilisant le chemin leplus rapide pour chaque situation.

    Donc comme nous le voyons, la dcision entre vrification de l'tat ou du comportement n'est pas une grosse dcisionla plupart du temps. La vraie difficult est de choisir entre TDD classique et orient-simulacre. Il apparat que lescaractristiques de la vrification de l'tat et du comportement affectent cette discussion, et c'est l que je vaisfocaliser mon nergie.

    Mais avant de le faire, je vais proposer un cas limite. De temps en temps vous rencontrez des choses dont il estvraiment difficile de vrifier l'tat, mme s'il ne s'agit pas de collaborations compliques. Un bon exemple de celaest un cache. La particularit d'un cache est que vous ne pouvez pas dire partir de son tat comment le cache afonctionn - c'est un cas o la vrification du comportement serait un choix sage mme pour un adepte pur et dur dustyle TDD classique. Je suis sr qu'il y a d'autres exceptions dans les deux directions.

    Maintenant que nous approfondissons le choix entre styles classique/orient-simulacre, il y a des tas de facteurs considrer, donc je les ai organiss en groupes grossiers :

    Le guidage du TDD

    Les objets simulacres sont issus de la communaut XP, et l'une des caractristiques principales de XP est soninsistance sur le Dveloppement Dirig par les Tests - dans lequel la conception d'un systme volue par desitrations pilotes par l'criture de tests.

    Ainsi il n'y a rien de surprenant ce que les adeptes du style orient-simulacre parlent de l'effet sur la conceptiondu test avec des simulacres. En particulier ils recommandent un style appel Dveloppement Dirig par les Besoins.Avec ce style vous commencez dvelopper une histoire utilisateur en crivant votre premier test pour l'extrieur devotre systme, en faisant d'un certain objet interface votre SCT. En rflchissant aux attentes sur les collaborateurs,vous explorez les interactions entre le SCT et ses voisins - et donc vous concevez effectivement l'interface externedu SCT.

    Une fois que vous avez votre premier test qui tourne, les attentes sur les simulacres fournissent les spcificationspour la prochaine tape, et un point de dpart pour les tests. Vous transformez chaque attente en un test sur uncollaborateur et rptez le processus en progressant dans le systme un SCT la fois. Ce style est galement nomm"extrieur-vers-intrieur", ce qui en est une trs bonne description. Il fonctionne bien avec les systmes organiss encouches. Vous commencez d'abord en programmant l'interface utilisateur en utilisant des simulacres des couchessous-jacentes. Ensuite vous crivez vos tests pour la couche en-dessous, en parcourant graduellement le systmeune couche la fois. C'est une approche trs structure et trs contrle, dont beaucoup de gens pensent qu'elleest utile pour guider les novices dans la programmation oriente-objet et le TDD.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 14 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Le TDD classique ne fournit pas tout fait le mme guidage. Vous pouvez faire une approche progressive similaire,en utilisant des mthodes bouchons la place de simulacres. Pour faire cela, chaque fois que vous avez besoin dequelque chose d'un collaborateur, vous codez simplement en dur la rponse ncessaire pour faire marcher le SCT.Une fois que vous avez la barre verte vous remplacez la rponse en dur par le code appropri.

    Mais le TDD classique peut faire d'autres choses galement. Un style courant est "milieu-vers-extrieur". Dansce style vous prenez une fonctionnalit et dcidez ce dont vous avez besoin dans le domaine pour que cettefonctionnalit marche. Vous faites faire aux objets du domaine ce dont vous avez besoin, et une fois qu'ils marchentvous tablissez l'interface utilisateur au-dessus. En faisant cela vous pouvez trs bien ne rien avoir doubler du tout.Beaucoup de gens aiment cette approche car elle concentre l'attention sur le modle du domaine d'abord, ce quiempche la logique du domaine de contaminer l'interface utilisateur.

    Je voudrais souligner que les adeptes des styles orient-simulacre et classique font cela une seule histoire utilisateur la fois. Il y a une cole de pense qui construit les applications couche par couche, ne commenant pas unenouvelle couche tant que celle en cours n'est pas termine. Au contraire les adeptes du style classique et dessimulacres tendent avoir une approche agile et prfrent des itrations de petite taille. Par consquent ils travaillentfonctionnalit par fonctionnalit plutt que couche par couche.

    L'initialisation des classes de test

    Avec le TDD classique vous devez crer non pas seulement le SCT mais aussi tous les collaborateurs dont le SCT besoin pour rpondre au test. Bien que l'exemple ci-dessus n'ait que peu d'objets, les tests rels impliquent souventun grand nombre de collaborateurs. Habituellement ces objets sont crs et supprims lors de chaque excutiondes tests.

    Les tests avec simulacres, cependant, ont seulement besoin de crer le SCT et des simulacres pour sescollaborateurs immdiats. Ceci peut viter un peu du travail impliqu dans la construction de classes de testcomplexes (au moins en thorie. J'ai entendu des histoires d'initialisations de simulacres pas mal complexes, maiscela tait peu tre d une mauvaise utilisation des outils).

    En pratique les testeurs classiques tendent rutiliser autant que possible les initialisations de test complexes. Lamanire la plus simple est de mettre le code d'initialisation dans une mthode setup xUnit. Des initialisations pluscompliques peuvent avoir besoin d'tre utilises par plusieurs classes de test, alors dans ce cas vous crez desclasses spciales pour gnrer les initialisations. Je les appelle habituellement des Mres d'objets, en me basantsur une convention de nommage utilise dans un projet XP prcoce chez ThoughtWorks. Utiliser des mres estessentiel dans le test classique de grande envergure, mais les mres reprsentent du code supplmentaire qui abesoin d'tre maintenu, et tout changement au niveau des mres peut avoir des rpercussions en chane traversles tests. Il peut aussi y avoir une pnalit de performance l'initialisation - bien que je n'ai pas entendu dire quece soit un problme srieux si cela est fait correctement. La cration de la plupart des objets d'initialisation est bonmarch, et quand ce n'est pas le cas ils sont habituellement doubls.

    En consquence j'ai entendu chaque style accuser l'autre de reprsenter trop de travail. Les partisans des simulacresdisent que crer les initialisations est un gros effort, mais les classiques disent qu'elles sont rutilisables alors qu'ilfaut crer des simulacres pour chaque test.

    L'isolation des tests

    Si vous introduisez un bug dans un systme avec du test bas sur des simulacres, gnralement il fera choueruniquement les tests dont le SCT contient le bug. Avec l'approche classique, cependant, n'importe quel test d'objetclient peut aussi chouer, ce qui conduit des checs aux endroits o l'objet fautif est utilis comme collaborateurdans le test d'un autre objet. Par consquent, un chec dans un objet trs utilis cause une cascade d'checs detest travers le systme.

    Les testeurs utilisant des simulacres considrent cela comme un problme majeur; il conduit beaucoup de dbogagepour trouver la cause racine de l'erreur et la corriger. Cependant les classiques n'expriment pas cela comme une

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 15 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    source de problmes. Habituellement le coupable est assez facile identifier en examinant quels tests chouent etles dveloppeurs peuvent alors dire quels checs drivent de la cause racine. De plus si vous testez rgulirement(comme vous le devriez) alors vous savez que l'chec a t caus par ce que vous avez dit en dernier, donc iln'est pas difficile de trouver l'erreur.

    La granularit des tests peut tre un facteur significatif ici. Puisque les tests classiques mettent en jeu de nombreuxobjets rels, vous trouvez souvent un test particulier qui est le test primaire pour un groupe d'objets, plutt que pourun seul objet. Si ce groupe comprend beaucoup d'objets, alors trouver la vraie cause d'un bug peut tre beaucoupplus difficile. Ce qui arrive ici c'est ce que les tests ont une granularit trop grossire.

    Il est probable que les tests avec des simulacres sont moins enclins souffrir de ce problme, car la convention estde faire des simulacres pour tous les objets au-del de l'objet primaire, ce qui rend clair que des tests de granularitplus fine sont ncessaires pour les collaborateurs. Ceci tant dit, il est aussi vrai qu'utiliser des tests granularit tropgrossire n'est pas ncessairement un chec du test classique en tant que technique, c'est plutt d une mauvaiseapplication du test classique. Une bonne rgle empirique est de s'assurer d'isoler des tests de fine granularit pourchaque classe. Alors que des groupes sont parfois raisonnables, ils devraient tre limits un tout petit nombred'objets - pas plus qu'une douzaine. De plus, si vous vous trouvez face un problme de dbogage d des tests degranularit trop grossire, vous devriez dboguer dans une optique TDD, en crant des tests de plus fine granularitau fur et mesure que vous avancez.

    En l'essence les tests classiques xunit ne sont pas juste des tests unitaires, mais aussi de mini tests d'intgration. Parconsquent beaucoup de gens aiment le fait que des tests sur des clients peuvent attraper des erreurs que les testsprincipaux pour un objet auraient rates, en sondant particulirement les zones o les classes interagissent. Les testsavec les simulacres perdent cette qualit. De plus vous courrez aussi le risque que les attentes sur les simulacressoient incorrectes, ce qui rsulte en des tests unitaires qui passent au vert mais masquent des erreurs inhrentes.

    A ce stade je dois souligner que quelque soit le style de test que vous utilisez, vous devez le combiner avec destests d'acceptance de granularit plus grossire, tests qui oprent travers tout l'ensemble du systme. J'ai souventcrois des projets qui taient en retard dans l'utilisation de tests d'acceptance, et qui l'ont regrett.

    Le couplage des tests avec les implmentations

    Quand vous crivez un test avec simulacres, vous testez les appels du SCT vers l'extrieur pour vous assurer qu'ilparle correctement ses fournisseurs. Un test classique s'intresse uniquement l'tat final - pas la manire dontcet tat a t obtenu. Les tests avec simulacres sont ainsi plus fortement coupls l'implmentation d'une mthode.Changer la nature des appels aux collaborateurs cassera gnralement un test avec simulacre.

    Ce couplage entrane plusieurs proccupations. La plus importante est l'effet sur le TDD. Dans le cas des testsavec simulacres, crire le test vous fait rflchir l'implmentation du comportement - et en effet les testeurs avecsimulacres voient cela comme un avantage. Les classiques, cependant, pensent qu'il est important de rflchirseulement ce qui arrive de l'interface externe, et de laisser de ct toute considration d'implmentation jusqu'ce que vous ayez fini d'crire le test.

    Le couplage avec l'implmentation interfre galement avec le remaniement, puisque les changementsd'implmentation risquent beaucoup plus de casser les tests que dans le cas du test classique.

    Cela peut tre aggrav par la nature mme des boites outils de simulacres. Souvent les outils de simulacresspcifient des appels de mthodes et des appariements de paramtres trs spcifiques, mme quand ils ne sont paspertinents pour le test en question. Un des buts de la boite outils jMock est d'tre plus flexible dans sa spcificationdes attentes, pour autoriser le relchement des attentes dans les zones o elles n'ont pas d'importance, au prix del'utilisation de chanes qui rendent les remaniements plus dlicats.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 16 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Le style de conception

    Pour moi, l'un des aspects les plus fascinants de ces styles de test est la manire dont ils influencent les dcisions deconception. Comme j'ai parl avec les deux types de testeurs, je suis devenu conscient de quelques diffrences entreles conceptions encourages par les styles, mais je suis certain que je ne fais qu'gratigner la surface de ce sujet.

    J'ai dj mentionn une diffrence dans la manire d'aborder les couches. Les tests avec simulacres supportent uneapproche "extrieur-vers-intrieur" tandis que les dveloppeurs qui prfrent travailler partir du modle du domainetendent prfrer le test classique.

    A un niveau moins lev, j'ai not que les testeurs orients-simulacres tendent s'loigner des mthodes quiretournent des valeurs, pour favoriser les mthodes qui agissent sur un objet collecteur. Prenez l'exemple ducomportement consistant rassembler de l'information d'un groupe d'objets pour crer un rapport sous formede chane de caractres. Une manire courante de procder est d'avoir une mthode de rapport qui appelle surles diffrents objets des mthodes retournant des chanes, et qui assemble la chane rsultat dans une variabletemporaire. Un testeur orient-simulacre passera probablement un tampon de caractres aux diffrents objets et leurfera ajouter les diffrentes chanes ce tampon - traitant ainsi le tampon comme un paramtre collecteur.

    Les testeurs avec simulacres parlent galement plus d'viter les dsastres en chanes - les chanes de mthodesdu type getThis().getThat().getTheOther(). viter les chanes de mthodes est galement connu sous le nom dela Loi de Demeter. Alors que les chanes de mthodes sont une mauvaise odeur, le problme oppos des objetsintermdiaires boursoufls de mthodes de transfert est galement une mauvaise odeur. (J'ai toujours senti que jeserais plus confortable avec la Loi de Demeter si elle tait appele la Suggestion de Demeter).

    L'une des choses les plus difficiles comprendre dans la conception oriente-objet est le principe "Fais au lieu dedemander" qui vous encourage dire un objet de faire quelque chose, au lieu de lui extraire des donnes pourfaire la chose en question dans du code client. Les testeurs orient-simulacres disent que le test avec simulacresfavorise ce principe et vite les confettis de code "get..." qui se rpand dans beaucoup trop de code ces temps-ci.Les classiques avancent qu'il y a beaucoup d'autres manires de faire cela.

    Un problme reconnu avec la vrification d'tat est qu'elle peut conduire la cration de mthodes requtes servantseulement supporter la vrification. Il n'est jamais confortable d'ajouter des mthodes l'API d'un objet dans leseul but de tester; utiliser la vrification du comportement vite ce problme. Le contre-argument est que de tellesmodifications sont souvent mineures en pratique.

    Les testeurs orients-simulacres favorisent les interfaces de rles et assurent qu'utiliser ce style de test encouragela cration de plus d'interfaces de rles, puisque chaque collaboration a son propre simulacre et est donc plus sujette devenir une interface de rle. Ainsi dans mon exemple ci-dessus concernant la gnration d'un rapport en utilisantun tampon de caractres, un testeur orient-simulacre serait plus enclin inventer un rle particulier qui aurait dusens dans ce domaine, et qui pourrait tre implment par un tampon de chanes.

    Il est important de se rappeler que cette diffrence de style de conception est un lment de motivation cl pour laplupart des testeurs orients-simulacres. Les origines du TDD taient un dsir d'obtenir de solides tests automatissde rgression qui supporteraient une conception volutionnaire. Sur le chemin ses adeptes ont dcouvert qu'criredes tests d'abord reprsentait une amlioration significative du processus de conception. Les adeptes du style orient-simulacre ont une forte ide de quelle conception est une bonne conception, et ont dvelopp des bibliothques desimulacres principalement pour aider les gens dvelopper ce style de conception.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 17 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Faut-il tre un testeur classique ou orient-simulacres ?

    Je trouve qu'il est difficile de rpondre avec certitude. Personnellement j'ai toujours t un adepte du bon vieux TDDclassique et jusque-l je ne vois pas de raison de changer. Je ne vois aucun bnfice irrfutable pour le TDD avecsimulacres, et je suis proccup par les consquences de coupler les tests avec l'implmentation.

    Ceci me frappe particulirement quand j'observe un programmeur orient-simulacre. J'aime vraiment le fait quependant que vous crivez le test, vous vous concentrez sur le rsultat du comportement, pas sur comment il est fait.Un adepte des simulacres rflchit constamment l'implmentation du SCT pour pouvoir crire les attentes. Celame parat vraiment anti-naturel.

    Je souffre galement de l'inconvnient de ne pas essayer le TDD avec simulacres sur autre choses que desapplications jouets. Comme je l'ai appris du TDD lui-mme, il est souvent difficile de juger une technique sans l'essayersrieusement. Je connais beaucoup de bons dveloppeurs qui sont des adeptes convaincus et trs heureux dessimulacres. Donc bien que je sois toujours un classique convaincu, j'ai prfr prsenter les deux arguments aussiquitablement que possible de telle sorte que vous puissiez vous faire votre propre ide.

    Donc si le test avec simulacres vous parat attractif, je vous suggre de l'essayer. Cela en vaut particulirementla peine si vous avez des problmes dans certaines zones que le test avec simulacre est conu pour amliorer.Je vois deux zones principales ici. La premire si vous passez beaucoup de temps dboguer quand des testschouent, parce qu'ils n'chouent pas proprement et ne vous disent pas o est le problme. La deuxime si vosobjets ne contiennent pas suffisamment de comportements ; le test avec simulacres peut encourager l'quipe dedveloppement crer des objets plus riches en comportements.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 18 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Considrations finales

    Au fur et mesure que grandit l'intrt pour les outils xUnit et le Dveloppement Dirig par les Tests, de plus enplus de gens croisent les simulacres. Le plus souvent, ils apprennent une partie des outils pour simulacres, sanscomprendre compltement la division classique/orient-simulacre sur lesquels ils reposent. Quelque soit votre ctdans cette division, je pense qu'il est utile de comprendre cette diffrence de vue. Alors que vous n'avez pas besoind'tre orient-simulacres pour trouver pratiques les outils de simulacres, il est utile de comprendre le raisonnementqui guide la plupart des dcisions de conception du logiciel.

    Le but de cet article tait, et est toujours, de souligner ces diffrences et d'exposer les compromis entre elles. Il y a plusdans la rflexion oriente-simulacres que ce que j'ai eu le temps d'approfondir, en particulier ses consquences surle style de conception. J'espre que dans les toutes prochaines annes nous verrons plus de choses crites sur cela,et que cela approfondira notre comprhension des consquences fascinantes de l'criture de tests avant le code.

  • Tests unitaires et doublures de tests : les simulacres ne sont pas des bouchons par Martin Fowler - Bruno Orsier

    - 19 -Copyright Martin Fowler, all rights reserved.

    http://bruno-orsier.developpez.com/mocks-arent-stubs/

    Lectures complmentaires

    Pour une revue complte de la pratique du test unitaire avec xUnit, gardez un il sur le livre Gerard Meszaros quiva sortir (avertissement : il est dans mes sries). Il maintient aussi un site web avec les patrons du livre.

    Pour en savoir plus sur le TDD, il faut commencer par le livre de Kent.

    Pour en savoir plus sur le style de test orient-simulacre, le premier endroit visiter est le site mockobjects.com oSteve Freeman et Nat Price recommandent le point de vue orient-simulacre avec des papiers et un bon blog. Lisezen particulier l'excellent papier OOPSLA. Pour plus d'informations sur le Dveloppement Dirig par le Comportement,une variante du TDD trs oriente-simulacre, commencez par l'introduction de Dan North.

    Vous pouvez aussi en savoir plus sur ces techniques en allant voir les sites web des outils jMock, nMock, EasyMock,EasyMock.net (il y a d'autres outils disponibles, ne considrez pas cette liste comme complte).

    Le papier original sur les objets simulacres a t prsent XP2000, mais il est un peu dpass maintenant.

    SynopsisSommaireNotes du traducteurRemerciements

    IntroductionLes tests traditionnelsLes tests avec des objets simulacresUtilisation de EasyMock

    La diffrence entre les simulacres et les bouchonsLes styles de test classique et orient-simulacreComment choisir parmi les diffrences ?Le guidage du TDDL'initialisation des classes de testL'isolation des testsLe couplage des tests avec les implmentationsLe style de conception

    Faut-il tre un testeur classique ou orient-simulacres ?Considrations finalesLectures complmentaires