La maquette n'est pas une béquille, la maquette est une spécification

Parmi les nombreux pseudo-ides en orbite autour des TDD, il y a un certain mépris pour les doubles de test, notamment en raison de leurs noms ridicules.

Ils les appelleraient fièrement, sinon mok, stub, fake - un sentiment que nous ne perdons vraiment rien si nous ne l’utilisons pas. (Contrairement aux "tests d'intégration" et "dépendances réelles").

Cependant, vous pouvez changer le point de vue. En fin de compte, la maquette non seulement prend en charge le composant dépendant, mais pas tant, mais spécifie plutôt le comportement de la dépendance. Et la mise en œuvre «réelle» est une certaine incarnation actuelle, peut-être erronée, de notre fière idée.

En ce sens, chaque fois que nous écrivons

when(mockDependency.method(inputValue)).thenReturn(returnValue) ,

nous documentons certains comportements des composants.

Il y a donc plusieurs conséquences.

Les objets fictifs sont étroitement liés aux spécifications de test réelles, à la fois dans le vocabulaire et dans le sens. Cela et un autre nous concentrent sur les exigences et les scénarios, mais pas sur les fonctionnalités de l'implémentation actuelle.

Le fait que les déclarations sur un composant à mouiller lors de l'utilisation de frameworks comme Mockito soient un peu gênants pour nous sont dispersés parmi les classes clientes, et il est difficile de les suivre. Dans ce sens, les classes descendantes explicites avec un comportement prédéfini sont préférables aux mocks comme Mockito, car elles vous permettent d'encapsuler des scripts et de les visualiser en un coup d'œil.

Ainsi, les classes de script ValidOrderProviderStub, ExpiredOrderProviderStub, InvalidOrderIdException_OrderProviderStub, OnlyOnceOrderProvider et ainsi de suite, qui peuvent être dans le même package et utilisés par tous les tests à la fois, sont ajoutées à chaque classe OrderProvider.

Cela inclut des classes d'espionnage faciles à implémenter.

De plus, cette approche est plus rapide à exécuter et fonctionne sans réflexion.

Ainsi, lors de la lecture du code, on peut faire une convention selon laquelle la présence de mok confirme la possibilité d'un script, et son absence interdit l'existence d'un tel script. Si nous interdisons aux classes clientes d'écrire des attentes mockito, alors dans la recherche de NullOrderProvider, il s'avère qu'il n'y a pas de maquette appropriée, car null ne revient jamais, et donc cela n'a aucun sens de tester ce scénario.

Si mok est une spécification, alors mok est le reflet de nos plans pour un composant, et ils peuvent et doivent être écrits avant la mise en œuvre.

Si un mok est une spécification, il est hiérarchique et reflète le comportement du composant en fonction de certaines conditions.

Ainsi, notre moki peut trop se multiplier: les moki inconditionnels retournant toujours les mêmes, ainsi que les moki avec des conditions internes, telles que forIdOne_returningOne_forIdTwo_ReturningTwo_OrderProvider. La dernière énumération et il vous suffit de créer un FakeOrderProvider avec le comportement approprié, qui doit être synchronisé avec l'implémentation réelle.

Par conséquent, si un mok est une spécification d'un certain comportement, la mise en œuvre d'un composant n'est rien d'autre que synchroniser le comportement d'un composant avec ses moks.

Et c'est peut-être là le principal argument contre les foules - la nécessité de synchroniser leur comportement avec la mise en œuvre réelle actuelle, nous en parlerons séparément la prochaine fois.

Source: https://habr.com/ru/post/fr474484/


All Articles