TDD - Outside In vs Inside Out

53

Quelle est la différence entre la construction d’une application Outside In et sa construction Inside Out avec TDD?

Voici des ouvrages sur le TDD et les tests unitaires que j'ai lus:
Développement piloté par les
tests : Exemple Développement piloté par les tests: Guide pratique: Guide pratique
Solutions concrètes pour le développement
piloté par les tests et les frameworks PHP de haute qualité sous Microsoft.
Schémas de test NET xUnit: Code de test de refactoring
L'art du test unitaire: avec des exemples dans .NET
, logiciel orienté objet en pleine croissance, guidé par des tests ---> Celui-ci était vraiment difficile à comprendre car JAVA n'est pas mon langage principal :)

Presque tous ont expliqué les bases de TDD et les tests unitaires en général, mais avec une faible mention des différentes manières de construire l’application.

Une autre chose que j'ai remarquée est que la plupart de ces livres (sinon tous) ignorent la phase de conception lors de l'écriture de l'application. Ils se concentrent davantage sur la rédaction rapide des scénarios de test et sur la conception propre à la conception.

Cependant, je suis tombé sur un paragraphe de xUnit Test Patterns qui traitait de la façon dont les gens abordent TDD. Il y a 2 écoles là-bas, Outside In vs Inside Out .

Malheureusement, le livre ne développe pas plus sur ce point. Je souhaite savoir quelle est la principale différence entre ces 2 cas.
Quand devrais-je utiliser chacun d'eux?
Pour un débutant TDD, lequel est le plus facile à comprendre?
Quels sont les inconvénients de chaque méthode?
Existe-t-il des documents traitant spécifiquement de ce sujet?

Songo
la source
Les deux approches sont décrites sur le site XUnit Test Patterns: xunitpatterns.com/Philosophy%20Of%20Test%20Automation.html . C'est bizarre qu'ils ne soient pas dans le livre.
guillaume31

Réponses:

45

Inside-Out et Outside-In sont des termes assez rares. Plus souvent, j'ai entendu parler de l' école classique et de l' école londonienne .

  • Inside-Out (Classique, bottom-up ): vous commencez au niveau composant / classe (à l'intérieur) et ajoutez des tests aux exigences. À mesure que le code évolue (en raison de la refactorisation), de nouveaux collaborateurs, interactions et autres composants apparaissent. TDD guide complètement la conception.

  • Outside-in (école de Londres, de haut en bas ou « simulacres TDD » comme Martin Fowler appellerait): vous savez sur les interactions et les collaborateurs initiaux ( en particulier ceux au niveau haut) et commencer là - bas (niveau haut), se moquant des dépendances nécessaires. Avec chaque composant fini, vous passez aux collaborateurs précédemment moqués et recommencez avec TDD, créant ainsi des implémentations réelles (qui, bien qu'utilisées, n'étaient pas nécessaires auparavant grâce aux abstractions ). Notez que l' approche par l' extérieur va bien avec le principe YAGNI .

Aucune des approches n'est la seule et unique ; ils ont tous deux leur place en fonction de ce que vous faites. Dans les grandes solutions d'entreprise, où une partie de la conception provient d'architectes (ou existe déjà), on pourrait commencer par une approche "à la londonienne". D'autre part, lorsque vous ne savez pas exactement à quoi votre code devrait ressembler (ou comment il devrait s'intégrer dans d'autres parties de votre système), il peut être plus facile de commencer avec un composant bas de gamme et de le laisser évoluer à mesure que d’autres tests, modifications et exigences sont introduits.

Quoi que vous utilisiez, le plus souvent, c'est situationnel.

Pour en savoir plus, il y a un article dans le groupe Google avec une discussion assez intéressante sur l'origine de cette distinction et les raisons pour lesquelles Londres pourrait ne pas être le nom le plus approprié.

km
la source
2
Intéressant. Comment en êtes-vous arrivé à la conclusion que TDD est un mockist "extérieur"? Je préfère de loin la pensée et la conception Outside-In et donc les tests (voir softwareonastring.com/2015/01/10/… ), mais l'article de Fowler me met fermement avec Fowler dans le camp des classicistes. Même si mockist peut toujours utiliser une approche externe, vous ne pouvez pas le renverser et dire que la conception et les tests externes sont dodiques. L'extérieur peut être et est très pratiqué par les TDD classiques.
Marjan Venema
@jimmy_keen - Avec external-in, remplacez-vous à tout moment les modèles dans les tests de niveau supérieur avec les implémentations réelles créées ultérieurement? Ou les laissez-vous comme des dépendances simulées, puis exercez-vous le code de production dans son ensemble comme test d'intégration?
thehowler
1
Je ne suis pas d'accord pour dire que Classic / Mockist et Inside-Out / Outside-In sont liés. Ils sont orthogonaux. Vous pouvez utiliser Inside-Out / Outside-In avec l'un ou l'autre.
Daniel Kaplan
D'accord avec Daniel. Vous comparez deux taxonomies différentes. Bien que le développement extérieur soit souvent associé à l'école londonienne (mockist), ce n'est pas toujours le cas.
guillaume31
Je ne pense pas que ce soit une description correcte du processus d'inclusion. Il s'agit de tester à partir des interfaces publiques sans couplage avec les internes, autant que possible.
mcintyre321
15

Réponse courte: Comme d'habitude, cela dépendra de votre préférence en matière de codage et de votre approche d'équipe.

Le codage intérieur est génial parce que vous avez toujours quelque chose qui fonctionne. L'inconvénient est que cela ne vous aide pas nécessairement à vous rendre dans un endroit radicalement différent. Il est plus difficile de tracer un parcours de cette façon. De même, écrire du code de l' extérieur à l'intérieur ne présente pas l'inconvénient de ne pas nécessairement bénéficier d'un développement itératif rapide, ni de voir nécessairement toutes les opportunités et tous les schémas pouvant découler de la profondeur de la structure du code.

J'en suis venu à croire que les deux styles de développement sont importants et qu'il est en fait utile de combiner différents styles au sein d'une équipe. L'idée est que l'intérieur est idéal pour créer des blocs de construction, et l'extérieur dans la réflexion fournit une structure de forme et une direction.

Une partie de mon raisonnement vient d'une école de pensée très populaire qui favorise actuellement le développement itératif, qui est souvent synonyme de développement interne. Je pense que le développement itératif est génial quand on n'a pas trop à faire. Mais je pense que la réflexion dans son ensemble, par opposition à un processus purement itératif, est inestimable pour certains types d’innovation et pour parvenir à un endroit moins évident. Correctement gérée, à la fois dedans et dehors, peut être une combinaison très efficace.

EL Yusubov
la source
8

Vous devez ajouter les principes, les modèles et les pratiques agiles en C # à cette liste. Je ne sais pas pourquoi il a ajouté "en C #" à la fin. Les livres ne sont pas du tout la langue et la seule raison pour laquelle il n'a pas obtenu 5 étoiles sur amazon vient de gens qui ont été déçus par le C # de ses exemples.

L'auteur plaide pour que, chaque fois que cela est possible, vous devriez essayer d'écrire du code de l'extérieur et s'appuyer fortement sur une conception évolutive, et je suis d'accord avec sa déclaration. Son raisonnement est que, à mesure que nous ajoutons des fonctionnalités, notre conception évoluera toujours. Si nous commençons avec des composants de bas niveau au fur et à mesure de l'ajout de fonctionnalités, nous réalisons que ces composants ne font pas ce que nous voudrions qu'ils fassent, ou que les choses doivent être déplacées. Cela peut devenir assez coûteux, en particulier si, chaque fois que vous déplacez une fonctionnalité d'une classe à une autre, vous devez effectuer le même déplacement dans tous les projets de test unitaire.

D'autre part, si vous déterminez ce que votre application est censée faire en premier lieu, vous codez pour une interface externe. Au fur et à mesure que la taille des fonctionnalités augmente et que la taille du code testé augmente, vous refactorisez votre application en plusieurs classes, mais tant que cet effort de refactoring est en cours, les tests unitaires d'origine que vous avez écrits restent valides. Vous commencez donc complètement à l'extérieur et continuez à refactoriser dans de plus en plus de classes de bas niveau, tout en ajoutant des tests unitaires à ces classes internes, mais vous auriez rarement à vous déplacer et à réécrire vos tests unitaires.

Toutefois, si vous identifiez un sous-système de bas niveau spécifique dont votre application aura besoin (et peut-être que votre entreprise a déjà besoin de ce sous-système dans d'autres applications), le moment est opportun pour commencer par un bloc de construction de bas niveau, puis construire l'application en plus de cela.

DXM
la source
7

À mon sens, le concept de développement extérieur se développe réellement sur 2 niveaux. Gerard Meszaros les décrit brièvement comme "une conception externe" et un " codage extérieur-interne / interne-externe ".

  • Le premier niveau est un niveau d'organisation et de processus. La conception extérieure est conçue par opposition à une approche descendante (cascade / tayloriste) et une approche ascendante. Avec une approche externe, nous nous concentrons sur le point de vue de l'utilisateur final. Nous commençons avec des tests d’histoire, des tests ATDD ou BDD et nous passons «à l’intérieur» en déduisant des tests techniques et du code. La conception externe est donc ce que vous feriez dans un contexte agile. Dan North parle beaucoup de BDD, des approches descendantes, ascendantes et externes.

  • Le deuxième niveau est technique et concerne les couches applicatives. Le codage extérieur-intérieur signifie essentiellement à partir de l'interface utilisateur et à destination de la couche centrale (généralement la couche métier / domaine). Cela signifie non pas un codage interne qui commence par la couche centrale et qui code pour les couches externes en dernier.

Vous pouvez donc avoir une conception externe avec un codage externe ou un codage interne.

Je suis en désaccord avec Meszaros lorsqu'il associe un codage interne à un test d'intégration, affirmant que, dans un contexte interne, "nous ne testons pas réellement le logiciel externe indépendamment du logiciel interne". Mais je crois que rien ne vous empêche de le faire. Vous pouvez parfaitement choisir de tester vos objets de calque externe en les imitant même si le code de production existe déjà. Il vous suffit d'ajouter des interfaces et de simuler des objets concrets existants au lieu d'écrire les interfaces, de les imiter puis de créer les implémentations plus tard, comme vous le feriez avec un codage externe.

En d’autres termes, le format TDD de style fictif ou classique est un problème orthogonal au codage extérieur-dedans / dedans. Vous pouvez parfaitement utiliser un style mockist avec une approche à l'envers. La raison derrière ceci est que le style mockist / classicist concerne les dépendances de code alors que le codage extérieur-dedans / dedans-dehors concerne les couches applicatives .

Une autre chose importante est que les dépendances ne se limitent pas aux calques, elles existent également entre les objets du même calque. Par exemple, vous voudrez peut-être commencer avec un objet de votre couche de gestion centrale (approche inversée) et utiliser des simulacres pour isoler votre objet des autres objets de couche de gestion avec lesquels il parle. Cela se produit souvent avec IoC - les abstractions dont dépend votre objet sont souvent déclarées dans le même calque, mais les implémentations concrètes se trouvent dans un calque différent.

Robert "Uncle Bob" Martin mentionne brièvement le codage de bout en bout et explique comment il n'entre pas nécessairement en conflit avec une architecture découplée dans son post " Architecture propre ".

guillaume31
la source