La perspective:
Faisons donc un pas en arrière et demandons ce que TDD essaie de nous aider. TDD essaie de nous aider à déterminer si notre code est correct ou non. Et par correct, je veux dire "le code répond-il aux exigences de l'entreprise?" Le point de vente est que nous savons que des changements seront nécessaires à l'avenir, et nous voulons nous assurer que notre code reste correct après avoir effectué ces changements.
J'apporte cette perspective parce que je pense qu'il est facile de se perdre dans les détails et de perdre de vue ce que nous essayons de réaliser.
Principes - SAP:
Bien que je ne sois pas un expert en TDD, je pense que vous manquez une partie de ce que le principe d'assertion unique (SAP) essaie d'enseigner. SAP peut être reformulé comme «tester une chose à la fois». Mais TOTAT ne déroule pas aussi facilement que SAP.
Tester une chose à la fois signifie que vous vous concentrez sur un cas; un chemin; une condition aux limites; un cas d'erreur; un que ce soit par test. Et l'idée directrice derrière cela est que vous devez savoir ce qui s'est cassé lorsque le scénario de test échoue, afin de pouvoir résoudre le problème plus rapidement. Si vous testez plusieurs conditions (c.-à-d. Plus d'une chose) dans un test et que le test échoue, alors vous avez beaucoup plus de travail sur vos mains. Vous devez d'abord identifier lequel des multiples cas a échoué, puis comprendre pourquoi ce cas a échoué.
Si vous testez une chose à la fois, votre champ de recherche est beaucoup plus petit et le défaut est identifié plus rapidement. Gardez à l'esprit que «tester une chose à la fois» ne vous empêche pas nécessairement de regarder plus d'une sortie de processus à la fois. Par exemple, lorsque je teste un "bon chemin connu", je peux m'attendre à voir une valeur résultante spécifique foo
ainsi qu'une autre valeur dans bar
et je peux le vérifier foo != bar
dans le cadre de mon test. La clé est de regrouper logiquement les contrôles de sortie en fonction du cas testé.
Principes - PMP:
De même, je pense que vous manquez un peu ce que le principe de méthode privée (PMP) doit nous enseigner. PMP nous encourage à traiter le système comme une boîte noire. Pour une entrée donnée, vous devriez obtenir une sortie donnée. Peu importe comment la boîte noire génère la sortie. Vous vous souciez seulement que vos sorties s'alignent avec vos entrées.
PMP est vraiment une bonne perspective pour regarder les aspects API de votre code. Il peut également vous aider à définir ce que vous devez tester. Identifiez vos points d'interface et vérifiez qu'ils respectent les termes de leurs contrats. Vous n'avez pas besoin de vous soucier de la façon dont les méthodes derrière l'interface (alias privées) font leur travail. Vous avez juste besoin de vérifier qu'ils ont fait ce qu'ils étaient censés faire.
TDD appliqué ( pour vous )
Votre situation présente donc un peu une ride au-delà d'une application ordinaire. Les méthodes de votre application sont dynamiques, leur sortie dépend donc non seulement de l'entrée, mais aussi de ce qui a été fait précédemment. Je suis sûr que je devrais <insert some lecture>
ici que l'état soit horrible et bla bla bla, mais cela n'aide vraiment pas à résoudre votre problème.
Je vais supposer que vous avez une sorte de tableau de diagramme d'état qui montre les différents états potentiels et ce qui doit être fait pour déclencher une transition. Si vous ne le faites pas, vous en aurez besoin car cela aidera à exprimer les exigences commerciales de ce système.
Les tests: Tout d'abord, vous allez vous retrouver avec un ensemble de tests qui décident d'un changement d'état. Idéalement, vous aurez des tests qui exercent toute la gamme des changements d'état qui peuvent se produire, mais je peux voir quelques scénarios où vous n'aurez peut-être pas besoin d'aller aussi loin.
Ensuite, vous devez créer des tests pour valider le traitement des données. Certains de ces tests d'état seront réutilisés lors de la création des tests de traitement des données. Par exemple, supposons que vous ayez une méthode Foo()
qui a différentes sorties en fonction des états Init
et State1
. Vous voudrez utiliser votre ChangeFooToState1
test comme une étape de configuration afin de tester la sortie lorsque " Foo()
est dedans State1
".
Il y a certaines implications derrière cette approche que je veux mentionner. Spoiler, c'est là que j'exaspère les puristes
Tout d'abord, vous devez accepter que vous utilisiez quelque chose comme test dans une situation et une configuration dans une autre situation. D'une part, cela semble être une violation directe de SAP. Mais si vous définissez logiquement ChangeFooToState1
deux objectifs, vous respectez toujours l'esprit de ce que SAP nous enseigne. Lorsque vous devez vous assurer que les Foo()
états changent, vous l'utilisez ChangeFooToState1
comme test. Et lorsque vous avez besoin de valider Foo()
la sortie de "lorsque State1
vous êtes", vous l'utilisez ChangeFooToState1
comme configuration.
Le deuxième élément est que d'un point de vue pratique, vous n'allez pas vouloir de tests unitaires entièrement randomisés pour votre système. Vous devez exécuter tous les tests de changement d'état avant d'exécuter les tests de validation de sortie. SAP est en quelque sorte le principe directeur derrière cette commande. Pour indiquer ce qui devrait être évident - vous ne pouvez pas utiliser quelque chose comme configuration s'il échoue comme test.
Mettre ensemble:
À l'aide de votre diagramme d'état, vous générez des tests pour couvrir les transitions. Encore une fois, en utilisant votre diagramme, vous générez des tests pour couvrir tous les cas de traitement des données d'entrée / sortie pilotés par l'état.
Si vous suivez cette approche, les bloated, complicated, long, and difficult to write
tests devraient être un peu plus faciles à gérer. En général, ils devraient finir plus petits et être plus concis (c'est-à-dire moins compliqués). Vous devriez noter que les tests sont également plus découplés ou modulaires.
Maintenant, je ne dis pas que le processus sera complètement indolore car écrire de bons tests demande un certain effort. Et certains d'entre eux seront toujours difficiles car vous mappez un deuxième paramètre (état) sur un certain nombre de vos cas. Et en passant, il devrait être un peu plus clair pourquoi un système sans état est plus facile à construire pour les tests. Mais si vous adaptez cette approche à votre application, vous devriez constater que vous êtes en mesure de prouver que votre application fonctionne correctement.