Quelle est la différence entre les tests d’intégration et les tests unitaires?

Je connais la soi-disant définition des manuels scolaires des tests unitaires et des tests d’intégration. Ce qui m’intéresse, c’est quand il est temps d’écrire des tests unitaires … Je vais les écrire pour couvrir autant d’ensembles de classes que possible.

Par exemple, si j’ai une classe Word , je rédigerai des tests unitaires pour la classe Word . Ensuite, je commence à écrire ma classe de Sentence et quand il doit interagir avec la classe Word , j’écris souvent mes tests unitaires de manière à ce qu’ils testent à la fois Sentence et Word … au moins aux endroits où ils interagissent.

Ces tests sont-ils essentiellement des tests d’intégration, car ils testent désormais l’intégration de ces 2 classes ou s’agit-il d’un test unitaire couvrant 2 classes?

En général, à cause de cette ligne incertaine, j’écrirai rarement des tests d’intégration … ou est-ce que j’utilise le produit fini pour voir si tous les éléments fonctionnent correctement, même s’ils sont manuels et rarement répétés au-delà de la scope de chaque caractéristique individuelle?

Est-ce que je comprends mal les tests d’intégration ou y a-t-il vraiment très peu de différence entre les tests d’intégration et les tests unitaires?


modifier

Merci pour toutes les bonnes réponses à tous! Je pense que des réponses variées, il est clair que la ligne entre les tests unitaires et les tests d’intégration est définitivement floue, et peut-être est-ce un peu pédant d’essayer de savoir lesquels et quels sont les vrais objectives (Merci @Rob Cooper ). Aussi, désolé, mais je ne vais pas accepter de réponse parce que trop de gens sont trop bons, et cela semble vraiment subjectif.

Pour moi, la principale différence réside dans le fait que les tests d’intégration révèlent si une fonctionnalité fonctionne ou est cassée, car ils insistent sur le code dans un scénario proche de la réalité. Ils invoquent une ou plusieurs méthodes ou fonctionnalités logicielles et vérifient s’ils agissent comme prévu.

À l’inverse, un test d’unité testant une seule méthode repose sur l’hypothèse (souvent erronée) que le rest du logiciel fonctionne correctement, car il corrige explicitement chaque dépendance.

Par conséquent, lorsqu’un test unitaire pour une méthode mettant en œuvre une fonctionnalité est vert, cela ne signifie pas que la fonctionnalité fonctionne.

Disons que vous avez une méthode quelque part comme ceci:

 public SomeResults DoSomething(someInput) { var someResult = [Do your job with someInput]; Log.TrackTheFactYouDidYourJob(); return someResults; } 

DoSomething est très important pour votre client: c’est une fonctionnalité, la seule chose qui compte. C’est pourquoi vous écrivez généralement une spécification Cucumber qui l’affirme: vous souhaitez vérifier et communiquer que la fonctionnalité fonctionne ou non.

 Feature: To be able to do something In order to do something As someone I want the system to do this thing Scenario: A sample one Given this situation When I do something Then what I get is what I was expecting for 

Aucun doute: si le test réussit, vous pouvez affirmer que vous fournissez une fonctionnalité de travail. C’est ce que vous pouvez appeler la valeur commerciale .

Si vous voulez écrire un test unitaire pour DoSomething vous devriez faire semblant (en utilisant des simulations) que le rest des classes et des méthodes fonctionnent (c’est-à-dire que toutes les dépendances utilisées par la méthode fonctionnent correctement) .

En pratique, vous faites quelque chose comme:

 public SomeResults DoSomething(someInput) { var someResult = [Do your job with someInput]; FakeAlwaysWorkingLog.TrackTheFactYouDidYourJob(); // Using a mock Log return someResults; } 

Vous pouvez le faire avec l’dependency injections, une méthode d’usine ou une structure de simulation ou simplement l’extension de la classe en cours de test.

Supposons qu’il y ait un bogue dans Log.DoSomething() . Heureusement, les spécifications Gherkin le trouveront et vos tests de bout en bout échoueront.

La fonctionnalité ne fonctionnera pas, car le Log est rompu, pas parce que [Do your job with someInput] ne fait pas son travail. Et, en passant, [Do your job with someInput] est la seule responsabilité de cette méthode.

Supposons également que Log est utilisé dans 100 autres fonctionnalités, dans 100 autres méthodes de 100 autres classes.

Oui, 100 fonctionnalités échoueront. Heureusement, 100 tests de bout en bout échouent également et révèlent le problème. Et oui, ils disent la vérité .

C’est une information très utile: je sais que j’ai un produit cassé. C’est aussi une information très déroutante: elle ne dit rien sur le problème. Il me communique le symptôme, pas la cause profonde.

Cependant, le test unitaire de DoSomething est vert, car il utilise un faux Log , conçu pour ne jamais se casser. Et oui, c’est clairement mentir . Il communique une fonctionnalité cassée fonctionne. Comment peut-il être utile?

(Si le test unitaire de DoSomething() échoue, assurez-vous que: [Do your job with someInput] contient des bogues.)

Supposons que ce soit un système avec une classe cassée: Un système avec une classe cassée

Un seul bogue va briser plusieurs fonctionnalités et plusieurs tests d’intégration échoueront.

Un seul bug va casser plusieurs fonctionnalités et plusieurs tests d'intégration échoueront

D’un autre côté, le même bug ne cassera qu’un seul test unitaire.

Le même bug ne cassera qu'un seul test d'unité

Maintenant, comparez les deux scénarios.

Le même bug ne cassera qu’un seul test unitaire.

  • Toutes vos fonctionnalités utilisant le Log cassé sont en rouge
  • Tous vos tests unitaires sont en vert, seul le test unitaire pour Log est en rouge

En fait, les tests unitaires pour tous les modules utilisant une fonctionnalité cassée sont en vert car, en utilisant des simulations, ils suppriment les dépendances. En d’autres termes, ils courent dans un monde idéal, complètement fictif. Et c’est le seul moyen d’isoler les bogues et de les chercher. Le test unitaire signifie se moquer. Si vous ne vous moquez pas, vous n’êtes pas un test unitaire.

La différence

Les tests d’intégration indiquent ce qui ne fonctionne pas. Mais ils ne servent à rien pour deviner où le problème pourrait être.

Les tests unitaires sont les seuls tests qui vous indiquent exactement se trouve le bogue. Pour dessiner ces informations, ils doivent exécuter la méthode dans un environnement simulé, où toutes les autres dépendances sont censées fonctionner correctement.

C’est pourquoi je pense que votre phrase “Ou est-ce juste un test unitaire qui couvre 2 classes” est en quelque sorte déplacée. Un test unitaire ne doit jamais couvrir 2 classes.

Cette réponse est fondamentalement un résumé de ce que j’ai écrit ici: les tests unitaires sont la raison pour laquelle je les aime .

Lorsque j’écris des tests unitaires, je limite la scope du code testé à la classe que j’écris actuellement en me moquant des dépendances. Si j’écris une classe de phrase et que la phrase dépend de Word, j’utiliserai un mot simulé. En moquant Word, je peux me concentrer uniquement sur son interface et tester les différents comportements de ma classe Sentence en interagissant avec l’interface de Word. De cette façon, je teste uniquement le comportement et l’implémentation de Phrase et ne teste pas en même temps l’implémentation de Word.

Une fois que j’ai écrit les tests unitaires pour vérifier que Phrase se comporte correctement lorsqu’il interagit avec Word sur la base de l’interface de Word, j’écris le test d’intégration pour vérifier que mes hypothèses sur les interactions sont correctes. Pour cela, je fournis les objects réels et j’écris un test qui utilise une fonctionnalité qui utilisera à la fois Phrase et Word.

Mes 10 bits: D

On m’a toujours dit que les tests unitaires consistaient à tester un composant individuel – qui devait être pleinement utilisé. Maintenant, cela a tendance à avoir plusieurs niveaux, puisque la plupart des composants sont constitués de pièces plus petites. Pour moi, une unité est une partie fonctionnelle du système. Donc, il doit fournir quelque chose de valeur (c’est-à-dire pas une méthode pour l’parsing de chaînes, mais peut-être un HtmlSanitizer ).

Tests d’intégration est la prochaine étape, il prend un ou plusieurs composants et s’assure qu’ils fonctionnent ensemble comme ils le devraient .. Vous êtes alors au-dessus des complexités de la façon dont les composants fonctionnent individuellement, mais quand vous entrez HTML dans votre HtmlEditControl , il en quelque sorte par magie sait si sa validité ou pas ..

C’est une vraie ligne mobile cependant… Je préfère me concentrer davantage sur le bon fonctionnement du code ^ _ ^

Les tests unitaires utilisent des simulacres

Ce dont vous parlez, ce sont des tests d’intégration qui testent l’intégralité de l’intégration de votre système. Mais lorsque vous effectuez des tests unitaires, vous devez tester chaque unité séparément. Tout le rest devrait être raillé. Donc, dans le cas de la classe Sentence , si elle utilise la classe Word , alors votre classe Word doit être moquée. De cette façon, vous ne testerez que votre fonctionnalité de classe Sentence .

Je pense que lorsque vous commencez à penser aux tests d’intégration, vous parlez davantage de couches physiques que de couches logiques.

Par exemple, si vos tests concernent la génération de contenu, il s’agit d’un test unitaire: si votre test ne concerne que l’écriture sur le disque, il s’agit toujours d’un test unitaire, mais une fois que vous avez testé alors vous avez vous-même un test d’intégration. Lorsque vous testez la sortie d’une fonction dans un service, il s’agit d’un test unitaire, mais une fois que vous effectuez un appel de service et que vous voyez si le résultat de la fonction est identique, alors c’est un test d’intégration.

Techniquement, vous ne pouvez pas tester une seule classe de toute façon. Que se passe-t-il si votre classe est composée de plusieurs autres classes? Est-ce que cela en fait automatiquement un test d’intégration? Je ne pense pas.

Test d’unité: Le test effectué sur une unité ou sur un plus petit logiciel. Fait pour vérifier si elle répond à ses spécifications fonctionnelles ou à la structure de conception prévue.

Test d’intégration: Test des modules associés pour leur fonctionnalité combinée.

en utilisant la conception de responsabilité unique, son noir et blanc. Plus d’une responsabilité, c’est un test d’intégration.

Par le test du canard (regards, charlatans, dandinettes, c’est un canard), c’est juste un test unitaire avec plus d’un object nouvellement créé.

Lorsque vous entrez dans mvc et que vous le testez, les tests de contrôleur sont toujours intégrés, car le contrôleur contient à la fois une unité de modèle et une unité de vue. Test de logique dans ce modèle, je voudrais appeler un test unitaire.

A mon avis, la réponse est “Pourquoi est-ce important?”

Est-ce parce que les tests unitaires sont quelque chose que vous faites et que les tests d’intégration sont quelque chose que vous ne faites pas? Ou vice versa? Bien sûr que non, vous devriez essayer de faire les deux.

Est-ce parce que les tests unitaires doivent être rapides, isolés, reproductibles, à validation automatique et rapides? Bien sûr que non, tous les tests devraient être ceux-ci.

C’est parce que vous utilisez des simulacres dans les tests unitaires mais vous ne les utilisez pas dans les tests d’intégration? Bien sûr que non. Cela impliquerait que si j’ai un test d’intégration utile, je ne suis pas autorisé à append un simulacre, craignant de devoir renommer mon test en “test unitaire” ou de le remettre à un autre programmeur pour travailler.

Est-ce parce que les tests unitaires testent une unité et les tests d’intégration testent un certain nombre d’unités? Bien sûr que non. De quelle importance pratique est-ce? La discussion théorique sur la scope des tests est en pratique rompue car le terme “unité” dépend entièrement du contexte. Au niveau de la classe, une unité peut être une méthode. Au niveau de l’assemblage, une unité peut être une classe et, au niveau du service, une unité peut être un composant. Et même les classes utilisent d’autres classes, alors quelle est l’unité?

C’est sans importance.

Les tests sont importants, PREMIER est important, diviser les cheveux en fonction des définitions est une perte de temps qui ne fait que confondre les nouveaux venus.

Pensez à la nature de vos tests dans les termes suivants:

  • Réduction du risque : c’est ce que sont les tests. Seule une combinaison de tests unitaires et de tests d’intégration peut vous permettre de réduire totalement les risques, car les tests unitaires ne permettent pas de tester l’interaction entre les modules et les tests d’intégration ne peuvent exercer que peu les fonctionnalités d’un module non sortingvial.
  • Effort d’écriture de test : les tests d’intégration permettent d’économiser de l’effort, car vous n’avez pas besoin d’écrire des stubs / fakes / mocks. Mais les tests unitaires peuvent également permettre de gagner en effort lors de la mise en œuvre (et de la maintenance!) De ces stubs / fakes / mocks plus faciles que de configurer la configuration de test sans eux.
  • Délai d’exécution du test : les tests d’intégration impliquant des opérations lourdes (telles que l’access à des systèmes externes tels que des bases de données ou des serveurs distants) ont tendance à être lents. Cela signifie que les tests unitaires peuvent être exécutés beaucoup plus fréquemment, ce qui réduit les efforts de débogage en cas d’échec, car vous avez une meilleure idée de ce que vous avez changé entre-temps. Cela devient particulièrement important si vous utilisez le développement piloté par les tests (TDD).
  • Effort de débogage : si les tests d’intégration échouent, mais qu’aucun des tests unitaires ne le fait, cela peut être très gênant, car il y a tellement de code impliqué qui peut contenir le problème. Ce n’est pas un gros problème si vous n’avez déjà modifié que quelques lignes – mais à mesure que les tests d’intégration se déroulent lentement, vous ne les avez peut-être pas exécutés si rapidement …

Rappelez-vous qu’un test d’intégration peut encore entraîner l’accrochage ou la falsification de certaines de ses dépendances. Cela fournit beaucoup de compromis entre les tests unitaires et les tests système (les tests d’intégration les plus complets, testant l’ensemble du système).

Une approche pragmatique serait donc la suivante: faites confiance aux tests d’intégration autant que vous le pouvez et utilisez des tests unitaires lorsque cela est trop risqué ou peu pratique. Cette manière de penser peut être plus utile que certaines discriminations dogmatiques des tests unitaires et des tests d’intégration.

Je pense que je voudrais encore appeler quelques classes interactives un test unitaire à condition que les tests unitaires pour class1 testent les fonctionnalités de class1, et les tests unitaires pour class2 testent ses fonctionnalités, et aussi qu’ils ne frappent pas la firebase database.

J’appelle un test un test d’intégration lorsqu’il parcourt la majeure partie de ma stack et atteint même la firebase database.

J’aime beaucoup cette question, car la discussion sur TDD me semble parfois un peu trop puriste, et il est bon pour moi de voir des exemples concrets.

Je fais la même chose – je les appelle tous des tests unitaires, mais à un moment donné, j’ai un “test unitaire” qui couvre tellement de choses que je le renomme souvent “..IntegrationTest” – seulement un changement de nom.

Je pense qu’il y a une suite de “tests atomiques” (test d’une petite classe ou d’une méthode) à des tests unitaires (niveau de classe) et des tests d’intégration – puis des tests fonctionnels (qui couvrent normalement beaucoup d’autres choses) – Il ne semble pas y avoir de coupure nette.

Si votre test configure des données, et peut-être charge une firebase database / un fichier, etc., alors c’est peut-être plus un test d’intégration (tests d’intégration que je trouve moins utilisés et plus de classes réelles, mais cela ne signifie pas du système).

Unit Testing est une méthode de test qui vérifie que les unités individuelles du code source fonctionnent correctement.

Integration Testing est la phase de test du logiciel dans laquelle des modules logiciels individuels sont combinés et testés en tant que groupe.

Wikipedia définit une unité comme la plus petite partie testable d’une application, qui en Java / C # est une méthode. Mais dans votre exemple de classe Word et Sentence, j’écrirais probablement les tests de phrase car je trouverais probablement excessif d’utiliser une classe de mots simulée pour tester la classe de phrases. Donc, phrase serait mon unité et mot est un détail de la mise en œuvre de cette unité.

Tests d’intégration: la persistance de la firebase database est testée.
Tests unitaires: l’access à la firebase database est simulé. Les méthodes de code sont testées.

Les tests unitaires testent une unité de travail ou un bloc de code si vous le souhaitez. Généralement effectué par un seul développeur.

Le test d’intégration fait référence au test effectué, de préférence sur un serveur d’intégration, lorsqu’un développeur valide son code dans un référentiel de contrôle de source. Les tests d’intégration peuvent être effectués par des utilitaires tels que le régulateur de vitesse.

Ainsi, vous effectuez vos tests unitaires pour vérifier que l’unité de travail que vous avez créée fonctionne et que le test d’intégration valide que tout ce que vous avez ajouté au référentiel n’a pas changé quelque chose.

Un peu académique cette question, n’est-ce pas? 😉 Mon sharepoint vue: Pour moi, un test d’intégration est le test de toute la partie, pas si deux parties sur dix vont ensemble. Notre test d’intégration montre si la version principale (contenant 40 projets) réussira. Pour les projets, nous avons des tonnes de tests unitaires. La chose la plus importante concernant les tests unitaires est que le test d’unité ne doit pas dépendre d’un autre test unitaire. Donc pour moi les deux tests que vous décrivez ci-dessus sont des tests unitaires, s’ils sont indépendants. Pour les tests d’intégration, cela ne doit pas être important.

J’appelle les tests unitaires de ces tests que la boîte blanche teste une classe. Toutes les dépendances requirejses par cette classe sont remplacées par de fausses (les simulacres).

Les tests d’intégration sont les tests où plusieurs classes et leurs interactions sont testées en même temps. Seules certaines dépendances dans ces cas sont falsifiées / simulées.

Je n’appellerais pas les tests d’intégration de Contrôleur à moins que l’une de leurs dépendances ne soit réelle (c’est-à-dire qu’elle ne soit pas falsifiée) (par exemple, IFormsAuthentication).

La séparation des deux types de tests est utile pour tester le système à différents niveaux. De plus, les tests d’intégration ont tendance à durer longtemps et les tests unitaires sont supposés être rapides. La différence de vitesse d’exécution signifie qu’ils sont exécutés différemment. Dans nos processus de développement, les tests unitaires sont exécutés à l’enregistrement (ce qui est bien parce qu’ils sont super rapides) et les tests d’intégration sont exécutés une fois / deux fois par jour. J’essaie et lance des tests d’intégration aussi souvent que possible, mais en général, bash la firebase database / écrire sur des fichiers / créer des fichiers / etc dans RPC ralentit.

Cela soulève un autre point important, les tests unitaires devraient éviter de toucher IO (par exemple, disque, réseau, db). Sinon, ils ralentissent beaucoup. Il faut un peu d’effort pour concevoir ces dépendances d’IO – je ne peux pas admettre que j’ai été fidèle à la règle des «tests unitaires doivent être rapides», mais si vous êtes, les avantages sur un système beaucoup plus grand deviennent très rapidement évidents .

Les exemples ci-dessus fonctionnent très bien et je n’ai pas besoin de les répéter. Je vais donc me concentrer sur l’utilisation d’exemples pour vous aider à comprendre.

Tests d’intégration

Les tests d’intégration vérifient si tout fonctionne ensemble. Imaginez une série de rouages ​​qui travaillent ensemble dans une montre. Un test d’intégration serait: la montre indique-t-elle l’heure exacte? Est-il toujours en train de dire l’heure exacte en 3 jours?

Tout ce que cela vous dit, c’est si l’ensemble fonctionne. Si cela échoue, cela ne vous dit pas exactement où cela échoue.

Tests unitaires

Ce sont des types de test vraiment spécifiques. Ils vous disent si une chose spécifique fonctionne ou échoue. La clé de ce type de test est qu’il ne teste qu’une seule chose en supposant que tout fonctionne correctement. C’est le point clé.

Exemple: développons ce point en utilisant un exemple:

  • Prenons une voiture comme exemple.
  • Test d’ intégration pour une voiture: par exemple, la voiture conduit à Echuca et retour. Si cela se produit, vous pouvez dire sans risque qu’une voiture fonctionne à partir d’un sharepoint vue global. C’est un test d’intégration. En cas d’échec, vous ne savez pas où cela se produit: est-ce le radiateur, la transmission, le moteur ou le carburateur? Tu n’as aucune idée. Cela pourrait être n’importe quoi.
  • Test unitaire pour une voiture: Que le moteur fonctionne. Ce test suppose que tout le rest de la voiture fonctionne correctement. De cette façon, si ce test d’unité particulier échoue: vous pouvez être certain que le problème réside dans le moteur. Vous pouvez ainsi isoler et résoudre rapidement le problème.

Les conséquences du mixage de vos tests d’intégration et unitaires:

  • Supposons que votre test d’intégration de voiture échoue. Il ne conduit pas avec succès à Echuca. Où est le problème?

  • Vous regardez dans votre test de moteur. Mais dans ce cas particulier, le test du moteur utilise des dépendances externes: il utilise un système de carburant spécial. Supposons que le test de l’unité moteur ait également échoué. En d’autres termes, le test d’intégration et le test de l’unité moteur ont échoué. Où est le problème? (Accordez-vous 10 secondes pour obtenir la réponse.) • Le moteur est-il en panne ou est-ce le système d’alimentation en carburant qui a causé la panne du moteur?

Vous voyez le problème ici? Vous ne savez pas ce qui échoue exactement. Si vous utilisez 10 dépendances, chacune de ces 10 dépendances pourrait avoir causé le problème – et vous ne saurez pas par où commencer. C’est pourquoi l’unité teste les simulacres pour supposer que tout fonctionne correctement.

J’espère que ça aide.

Ces tests sont-ils essentiellement des tests d’intégration, car ils testent désormais l’intégration de ces 2 classes? Ou est-ce juste un test unitaire qui couvre 2 classes?

Je pense Oui et Oui. Votre test unitaire couvrant 2 classes est devenu un test d’intégration.

Vous pouvez l’éviter en testant la classe Sentence avec mock implementation – classe MockWord, ce qui est important lorsque ces parties du système sont suffisamment grandes pour être implémentées par différents développeurs. Dans ce cas, Word est testé à l’unité, Phrase est une unité testée à l’aide de MockWord, puis Phrase est testée pour l’intégration avec Word.

L’exemple de différence réelle peut être suivi 1) Un tableau de 1 000 000 d’éléments est facilement testé et fonctionne parfaitement. 2) BubbleSort est facilement testé sur une série de 10 éléments et fonctionne parfaitement. 3) Les tests d’intégration montrent que quelque chose ne va pas.

Si ces parties sont développées par une seule personne, le problème le plus probable sera rencontré lors du test de l’unité par BubbleSoft, simplement parce que le développeur a déjà un tableau réel et qu’il n’a pas besoin d’une implémentation fictive.

De plus, il est important de se rappeler que les tests unitaires et les tests d’intégration peuvent être automatisés et écrits, par exemple, avec JUnit. Dans les tests d’intégration JUnit, on peut utiliser la classe org.junit.Assume pour tester la disponibilité des éléments d’environnement (par exemple, la connexion à la firebase database) ou d’autres conditions.