Quand dois-je écrire des tests d'intégration?

30

Selon les règles des tests unitaires TDD sont écrits avant le code de production, mais qu'en est-il des tests d'intégration qui exercent une interaction entre des objets câblés concrets (non fictifs)?

Doivent-ils être écrits avant les tests unitaires ou après le code de production juste pour tester le "câblage"?

Notez que je ne parle pas d'acceptation ou de tests fonctionnels mais de tests d'intégration de niveau inférieur.

Chedy2149
la source

Réponses:

49

Le livre Rspec , parmi d'autres ressources BDD, suggère un cycle comme celui-ci:

entrez la description de l'image ici

Essentiellement, le processus est le suivant:

While behaviour required
    Write an integration test for a specific behaviour
    While integration test failing
        Write a unit test to fulfil partial behavior
        While unit test failing
            Write code to make unit test pass
        Commit
        While refactoring can be done
            Refactor
            While unit test failing
                Write code to make unit test pass
            Commit
    Push

Avertissement: Il ne fait aucun doute dans mon esprit que cela conduit au meilleur code et au meilleur produit, mais cela peut prendre du temps. Il y a toutes sortes de difficultés autour des données et du déterminisme, quand il s'agit de dire que les tests d'intégration doivent toujours réussir. Ce n'est pas approprié dans toutes les circonstances; il suffit parfois de sortir des trucs de la porte.

Cela dit, avoir un processus idéal à l'esprit est super. Cela vous donne un point de départ.

pdr
la source
2
Merci @pdr mais j'ai précisé que je ne parlais pas de tests d'acceptation qui sont écrits avant / au début d'une itération, je suis intéressé par les tests d'intégration de niveau inférieur.
Chedy2149
@ chedy2149: Akkh. Vous avez manqué ce commentaire. Avant de retirer ma réponse, je pense que vous devriez être plus précis sur ce que vous entendez par "niveau inférieur" dans le contexte des tests d'intégration.
pdr
Niveau inférieur: quels comportements ne sont pas spécifiés par les utilisateurs ou les clients et qui sont utilisés pour tester les interactions classes / composants attendus par les développeurs.
Chedy2149
5
En fait, je ne pense pas que cela fasse une différence si vous mettez "test d'acceptation" ou "test d'intégration" dans cette image - c'est une vue idéalisée pour tout type de tests sur différents niveaux d'abstraction. Mais à mon humble avis, le vrai problème n'est pas que cela puisse "prendre du temps" - le vrai problème est que l'écriture de tests d'intégration "à l'avance" sur une interface publique qui est toujours conçue avec l'aide de TDD, c'est comme tirer sur une "cible en mouvement". ".
Doc Brown
@DocBrown donc votre réponse est après le code de production et avant la sortie?
Chedy2149
10

Un vrai projet m'a montré qu'il n'est pas possible d'écrire des tests unitaires, puis l'intégration et même la direction opposée est erronée :-) Donc, j'écris habituellement des tests unitaires avec ceux d'intégration.

Pourquoi? Permettez-moi d'écrire comment je vois les deux types de tests:

  1. Tests unitaires - En plus de Wikipédia et de toutes les informations connues, les tests unitaires vous aident à affiner votre conception , à améliorer votre modèle, vos relations. Le flux est simple: une fois que vous commencez à taper un nouveau projet / nouveau composant, la plupart du temps, vous créez une sorte de PoC . Lorsque vous avez terminé, vous disposez toujours de méthodes longues, de classes longues, de méthodes et classes non cohérentes, etc.

    Les tests unitaires vous aident à supprimer ces problèmes, car lorsque vous effectuez de véritables tests unitaires à l'aide de classes factices (sans dépendance à l'égard d'autres composants) décrites ci-dessus, il n'est pas possible de les tester. Le signe de base du code non testable est une grande partie moqueuse des tests car vous êtes obligé de vous moquer de nombreuses dépendances (ou situations)

  2. Tests d'intégration - des tests corrects et fonctionnels vous disent que votre nouveau composant (ou composants) fonctionne ensemble ou avec d'autres composants - c'est la définition habituelle. J'ai trouvé que les tests d'intégration vous aident principalement à définir le flux comment utiliser votre composant du côté des consommateurs .

    C'est vraiment important car cela vous dit parfois que votre API n'a pas de sens de l'extérieur.

Eh bien, que se passe-t-il une fois que j'ai écrit les tests unitaires et les tests d'intégration plus tard?

J'ai eu de belles classes, une conception claire, un bon constructeur, des méthodes courtes et cohérentes, IoC prêt, etc. , bizarre. Il était juste confus. J'ai donc réparé l'API selon son point de vue mais cela a également nécessité de réécrire de nombreux tests car j'ai été poussé à changer les méthodes et parfois même le flux comment utiliser l'API.

Eh bien, que se passe-t-il une fois que j'ai écrit les tests d'intégration et les tests unitaires plus tard?

J'ai un débit exact, une bonne convivialité. Ce que j'ai aussi, ce sont de grandes classes, du code non cohérent, pas de journalisation, de longues méthodes. Code de spaghetti

Quel est mon conseil?

J'ai appris le flux suivant:

  1. Développer le squelette de base de votre code
  2. Écrivez des tests d'intégration qui indiquent si cela a du sens du point de vue du consommateur. Le cas d'utilisation de base est suffisant pour l'instant. Le test ne fonctionne évidemment pas.
  3. Écrivez du code avec des tests unitaires pour chaque classe.
  4. Écrivez le reste / manque des tests d'intégration. Il serait préférable d'implémenter ces tests dans # 3 comment vous améliorez votre code.

Notez que j'ai fait une petite présentation sur les tests unitaires / d'intégration, voir la diapositive # 21 où le squelette est décrit.

Martin Podval
la source
5

Les tests unitaires sont utilisés pour tester le plus petit bit testable possible d'un logiciel dans une application et pour tester sa fonctionnalité. Chaque unité est testée séparément avant de les fusionner en parties ou en composants plus grands de l'application.

C'est là qu'interviennent les tests d'intégration :
ils testent ces pièces nouvellement créées qui se composent des unités précédemment testées lors de l'assemblage de ces pièces. Le meilleur cas serait d'écrire les tests à ce stade lors de l'écriture de l'application elle-même.

Ben McDougall
la source
Donc, votre réponse est après le code de production?
Chedy2149
Cela ne répond pas à la question. Il demande si le code de production est écrit après l'écriture des tests d'intégration. Votre réponse peut être prise de toute façon.
Reactgular
1
@MathewFoscarini - réponse mise à jour. J'espère que cela deviendra plus clair maintenant.
Ben McDougall
En ce qui concerne les tests unitaires, je m'oppose au "plus petit morceau de logiciel possible ". Testez ce qui est dans le contrat (par exemple les méthodes publiques d'un objet, les fonctions exportées d'une bibliothèque) parce que le contrat définit ce qui doit fonctionner. D'autres choses peuvent être testées, mais agir n'est donc pas seulement une perte de temps, mais contre-productif.
itsbruce
3

J'ai tendance à considérer les tests d'intégration comme très similaires aux tests unitaires. En cela, je traite un sous-ensemble du code comme une boîte noire. Les tests d'intégration ne sont donc qu'une boîte plus grande.

Je préfère les écrire avant le code de production. Cela a l'avantage de m'aider à me souvenir des morceaux que je n'ai pas encore câblés ou que j'ai légèrement changé un détail dans l'interaction des objets.

Schleis
la source
Il existe différents niveaux de test: test de composant de boîte blanche, test de composant d'intégration de boîte blanche. Test de boîte noire des composants, test de boîte noire d'intégration. Il existe également des tests de système d'intégration.
Alexander.Iljushkin
2

Mis à part les tests d'acceptation, j'ai tendance à écrire des tests d'intégration uniquement aux limites d'une application, pour vérifier qu'elle s'intègre bien avec des systèmes ou des composants tiers.

L'idée est de créer des objets adaptateurs qui traduisent de la façon dont le tiers parle de ce dont votre application a besoin et de tester ces traducteurs par rapport au système externe réel. Que vous fassiez ce test en premier ou en dernier est, je pense, moins important qu'avec vos tests unitaires réguliers, car

  • Les informations de conception fournies par TDD n'ont pas autant d'importance ici, car la conception est à peu près connue à l'avance et il n'y a généralement rien de terriblement complexe, vous mappez simplement les choses d'un système à un autre.

  • Selon le module / système que vous souhaitez aborder, cela peut nécessiter beaucoup d'exploration, de bricolage de configuration, de préparation des échantillons de données, ce qui prend du temps et ne s'intègre pas vraiment bien dans une courte boucle de rétroaction TDD.

Cependant, si vous vous sentez vraiment plus à l'aise de construire votre adaptateur progressivement par petites étapes sécurisées, je recommanderais certainement de passer d'abord le test, cela ne peut pas faire de mal.

Vous pouvez trouver des exemples de cette approche ici: http://davesquared.net/2011/04/dont-mock-types-you-dont-own.html (6ème paragraphe) http://blog.8thlight.com/eric- smith / 2011/10/27 / thats-not-yours.html

guillaume31
la source
vous parlez ici de tests d'intégration qui vérifient les interactions entre "notre système" et des bibliothèques tierces, que diriez-vous de tester des interactions sur une plateforme tout en développant un plug-in par exemple?
Chedy2149
Bien que je possède peu d'expérience avec le développement de plugins, je suppose qu'ils peuvent être différents car ils sont par nature étroitement couplés à l'application hôte, vous pouvez donc vouloir adopter pleinement cette intégration et décider que vous n'avez pas besoin d'une couche d'adaptateur. Dans ce cas, je serais très prudent quant aux performances des tests - selon l'application hôte, appeler son API directement dans un grand nombre de vos tests peut être très lent. Si vous en avez peur, vous pouvez toujours recourir à l'approche "couche supplémentaire d'abstraction" et utiliser des simulations + tests d'intégration sur les adaptateurs.
guillaume31
1

J'allais donc accepter la première réponse mais elle a été supprimée.
Pour résumer
Dans une itération donnée:

  1. Écrire un test unitaire
  2. Écrire le code de production
  3. Écrire des tests d'intégration pour tester les interactions

Gardez à l'esprit les tests d'intégration tout en 1 et 2 pour garantir la testabilité au niveau de l'intégration.

Les tests d'intégration ne sont pas nécessairement écrits de bout en bout à l'étape 3, ils peuvent être partiellement écrits entre les étapes 1 et 2.

Chedy2149
la source
3
Ce résumé ignore complètement la nature itérative du processus. Une fois que l'API de votre code de production est stable dans une certaine mesure, vous pouvez commencer à écrire des tests d'intégration, puis vous pouvez retravailler votre code de production et probablement modifier ou étendre vos tests d'intégration. Donc, dans la plupart des cas, vous n'écrivez pas de tests d'intégration après le code de production, vous effectuez généralement les deux dans une certaine mesure en parallèle. Et en fait, cela dépend aussi fortement du type de logiciel que vous travaillez. La pensée «noir et blanc» ne vous mène pas plus loin.
Doc Brown
Bon point, la réponse semble ignorer le caractère itératif du design par le refactoring.
Chedy2149
0

Les tests unitaires testent des blocs de code discrets au sein de votre projet.
Les tests d'intégration testent comment votre code s'interface avec d'autres codes: en d'autres termes, ils testent l' interface de votre code.

Écrire des tests unitaires lors du développement de code derrière une interface.
Écrivez des tests d'intégration lors du développement de l'interface ou de tout code qui implémente l'interface.

Cela signifie que vous écrirez parfois des tests d'intégration très tard dans un projet, car la majorité du travail est derrière l'interface: par exemple, un compilateur, un webservice particulier qui implémente plusieurs couches de logique ou .. quelque chose qui implique beaucoup de logique interne.

Cependant, si vous implémentez un ensemble de services REST ou refactorisez le modèle de données et ajoutez la prise en charge des transactions XA, vous allez commencer à développer des tests d'intégration presque immédiatement, car la plupart de votre travail est centré sur l'interface, que ce soit l'API REST ou comment le programme utilise le modèle de données.

Marco
la source
Seriez-vous d'accord pour dire que les tests unitaires sont des tests de boîte blanche et les tests d'intégration sont des tests de boîte noire?
Chedy2149
Malheureusement, cela dépend. Les technologies pour les tests d'intégration ont fait d'énormes améliorations ces dernières années (au moins dans le monde Java) afin que je puisse tester 1 classe - mais sur un serveur d'applications. La question devient alors: où est la frontière entre les tests unitaires et les tests d'intégration? Un test d'intégration lorsque vous testez votre code s'interface avec d'autres technologies, ou un test d'intégration lorsque vous testez l'ensemble de votre application - mais pas nécessairement dans l'environnement dans lequel il est censé s'exécuter?
Marco
En bref, dans certains cas, certains tests d'intégration sont des tests de boîte noire - mais pas dans tous les cas.
Marco
FYI: Wiki définit les tests d'intégration comme "la phase de tests logiciels dans laquelle les modules logiciels individuels sont combinés et testés en groupe"
Marco
Exactement, Marco. Il existe des intégrations à chaque niveau de composant. Niveau de code, niveau d'application, niveau système.
Alexander.Iljushkin