Quel est l'intérêt de l'exécution de tests unitaires sur un serveur CI?

98

Pourquoi voudriez-vous exécuter des tests unitaires sur un serveur CI?

Sûrement, au moment où quelque chose se met à maîtriser, un développeur a déjà exécuté tous les tests unitaires avant et corrige les erreurs qui auraient pu se produire avec son nouveau code. N'est-ce pas le but des tests unitaires? Sinon, ils viennent de commettre un code erroné.

Steve
la source
51
Nos développeurs ne sont pas autorisés à s’engager à maîtriser. Ils poussent vers une branche fonctionnelle, le serveur de CI fusionne ensuite avec le maître et exécute des tests. Si elles réussissent, alors les changements sont fusionnés à maîtriser. Donc, le code avec des tests cassés ne peut pas être sur le maître ...
Boris the Spider
2
@ BoristheSpider - très bon flux de travail en effet. masterdoit toujours être sain d'esprit et, de préférence, automatiquement déployé à chaque fusion dans un environnement intermédiaire pour le contrôle et l'assurance qualité internes.
Par Lundberg le
130
"Sûrement, au moment où quelque chose est validé, un développeur a déjà exécuté tous les tests unitaires et corrigé les erreurs pouvant survenir avec son nouveau code." Dans quel monde imaginaire vis-tu?
jpmc26
5
Dans certains secteurs, l’important n’est pas simplement d’exécuter les tests sur le code, mais bien d’exécuter les tests sur les fichiers binaires . L'exécution des tests sur la sortie du CI signifie que vous pouvez garantir le bon fonctionnement du produit livré, car le fichier binaire reçu par votre client est celui qui a réussi tous vos tests. Cela semble banal, mais cela peut parfois avoir un effet (celui que j'ai observé est celui de l'obscurcissement; sur des projets complexes, ou lorsqu'il est étrangement configuré, cela peut entraîner des problèmes dans la version masquée qui n'existait pas dans la version épurée).
Anaximander
5
"Bien sûr, au moment où quelque chose se met à maîtriser, un développeur a déjà exécuté tous les tests unitaires avant et corrige les erreurs qui auraient pu se produire avec son nouveau code." ... pas sûr que ce soit grave
chucksmash

Réponses:

224

Sûrement, au moment où quelque chose se met à maîtriser, un développeur a déjà exécuté tous les tests unitaires avant et corrige les erreurs qui auraient pu se produire avec son nouveau code.

Ou pas. Cela peut être dû à plusieurs raisons:

  • Le développeur n'a pas la discipline pour le faire
  • Ils ont oublié
  • Ils n'ont pas tout mis en place et ont poussé un set de commit incomplet (merci Matthieu M.
  • Ils ont seulement fait quelques tests, mais pas toute la suite (merci nhgrif )
  • Ils ont testé sur leur branche avant de fusionner (merci nhgrif * 2)

Mais le vrai problème est d'exécuter les tests sur une machine autre que la machine à développer. Celui qui est configuré différemment.

Cela aide à résoudre les problèmes où les tests et / ou le code dépendent de quelque chose de spécifique à une zone de développement (configuration, données, fuseau horaire, paramètres régionaux, etc.).

Voici d'autres bonnes raisons pour lesquelles CI construit des tests:

  • Tester sur différentes plates-formes autres que les principales plates-formes de développement, ce qui peut être difficile à faire pour un développeur. (merci TZHX )
  • Acceptation / Intégration / Fin à la fin / Des tests très longs peuvent être exécutés sur le serveur CI mais ne s'exécutent généralement pas sur une zone de développement. (merci Ixrec )
  • Un développeur peut faire un petit changement avant de pousser / valider (en pensant que c'est un changement sans danger et donc en ne faisant pas les tests). (merci Ixrec * 2)
  • La configuration du serveur CI n'inclut généralement pas tous les outils de développement ni la configuration et est donc plus proche du système de production.
  • Les systèmes CI construisent le projet à partir de zéro à chaque fois, ce qui signifie que les constructions sont répétables
  • Un changement de bibliothèque peut entraîner des problèmes en aval - un serveur de CI peut être configuré pour créer toutes les bases de code dépendantes, pas seulement celle de la bibliothèque.
Oded
la source
36
Autres raisons courantes: 1) Le serveur de CI peut exécuter des tests d’intégration / acceptation de haut niveau qui prennent trop de temps pour que les développeurs les exécutent toujours. 2) Le développeur les a exécutés puis a fait un petit changement avant de dire qu'ils étaient très certains de ne rien casser, mais nous voulons en être certains.
Ixrec
11
Une modification d'une dépendance exécute souvent également toutes les générations en aval. Si un changement effectué par un développeur casse quelque chose en aval, il est difficile de le voir lors de la modification d'une bibliothèque (par exemple, le changement d'un type de données sous-jacent d'un SortedSet à un HashSet (fournissant uniquement le contrat de Set) et une personne en aval a travaillé sur l'hypothèse erronée selon laquelle l'ensemble a été trié). Ne pas exécuter les tests (en aval) sur le serveur CI laisserait ce bogue s'infiltrer un moment.
2
@MichaelT Bonne prise. C'est en fait la cause de> 90% de nos échecs CI ces jours -ci , ne sais pas comment je l' ai oublié ...
Ixrec
34
De plus, les exécuter sur un environnement CI signifie généralement que vous configurez votre projet à partir de zéro , garantissant ainsi la répétabilité de votre construction .
Mgarciaisaia
5
En outre, deux modifications peuvent être validées, qui ont été testées séparément, mais se séparent (l'une supprime une API non utilisée et l'autre commence à l'utiliser).
Simon Richter
74

En tant que développeur qui n'exécute pas tous les tests d'intégration et unitaires avant de s'engager dans le contrôle de code source, je vais proposer ma défense ici.

Je devrais construire, tester et vérifier qu'une application s'exécute correctement sur:

  • Microsoft Windows XP et Vista avec le compilateur Visual Studio 2008.
  • Microsoft Windows 7 avec le compilateur Visual Studio 2010.
    • Oh, et le MSI construit pour chacun de ceux-ci.
  • RHEL 5 et 6 avec respectivement 4,1 et 4,4 (similaire à CentOS)
    • 7 bientôt. Woop-de-woop.
  • Fedora Workstation avec GCC pour les trois dernières versions récentes.
  • Debian (et ses dérivés comme Ubuntu) pour les trois dernières versions récentes.
  • Mac OSX dans les trois dernières versions récentes.
    • Et les paquets (rpm, dmg, etc.)

Ajoutez à cela Fortran (avec les compilateurs Intel et GNU), Python (et ses différentes versions en fonction du système d'exploitation) et les composants de script bash / bat et, eh bien, je pense que vous pouvez voir les choses se dérouler en spirale

Il me faudrait donc seize machines, pour pouvoir effectuer quelques tests plusieurs fois par jour. Ce serait presque un travail à plein temps que de gérer l'infrastructure pour cela. Je pense que presque tout le monde est d'accord pour dire que c'est déraisonnable, surtout en multipliant le nombre de personnes dans le projet. Nous avons donc laissé nos serveurs CI faire le travail.

Les tests unitaires ne vous empêchent pas de commettre un code erroné, ils vous disent s'ils savent que vous avez cassé quelque chose. Les gens peuvent dire que "les tests unitaires doivent être rapides" et continuer sur les principes, les modèles de conception et les méthodologies, mais en réalité, il est parfois parfois préférable de laisser les ordinateurs que nous avons conçus pour des tâches répétitives et monotones le faire et ne les impliquer que s'ils Dis-nous qu'ils ont trouvé quelque chose.

TZHX
la source
3
Les tests unitaires testent le code et non les configurations. Ce serait sérieusement inerte de votre part d'ajouter un nouveau test et de le jeter par-dessus le mur sans même le lancer localement au préalable ...
Robbie Dee
33
@RobbieDee J'ai bien peur de ne pas voir ce que tu veux dire? Je ne suggère pas créer de nouveaux tests sans tester les locaux, ou tout simplement commettre aveuglément les choses au contrôle des sources sans les tester vous - même, et je voudrais exécuter les tests sur ma propre machine - mais « configuration » n'a pas besoin d'être testé pour un comportement cohérent et il vaut mieux le faire assez rapidement lorsque le développeur est toujours dans cette zone que de trouver un problème lorsque l'équipe qui utilise principalement des Mac se réveille à quatre mille kilomètres et met à jour leurs copies.
TZHX
7
@RobbieDee Je dirais que TZHX effectuerait tous les tests localement s'il le pouvait, mais ce n'est pas le cas . Comme TZHX ne le peut pas, ils exécutent certains tests localement (ceux qui peuvent s'exécuter sur leur système de développement et qui sont suffisamment courts ou très pertinents pour le code modifié, par exemple), et laissent la batterie fonctionner sur le système CI. Assez raisonnable.
Muru
11
@RobbieDee: Il croit aux tests unitaires. Il les teste donc sur son Macbook air, puis passe et s’enregistre. Les serveurs de CI exécutant Red Hat, Solaris et Windows exécutent ensuite ces tests à nouveau. N'est-il pas agréable de savoir que ce que vous avez testé fonctionne également sur les plateformes de production?
Slebetman
2
@RobbieDee: J'ai souvent écrit des tests unitaires spécifiques à un certain compilateur sur une certaine plateforme. Prenons par exemple un sous-système graphique utilisant les instructions de processeur spécifiques à AMD (le concurrent d’Intel), disponibles uniquement sur la version 4.5 de g ++ (le compilateur GNU C ++) ou une version plus récente, mais il m’arrive de travailler sur un processeur Atom et un ICC (le processeur Intel C ++). Compilateur). Il serait absurde d'exécuter les tests AMD / g ++ 4.5 à chaque fois sur cette machine, mais il s'agit d'un code à tester avant sa publication. plus mon propre code indépendant du processeur doit être testé pour une interopérabilité correcte. Bien sûr, il y a des VM et des émulateurs, ...
phresnel
23

Outre l'excellente réponse de Oded:

  • Vous testez le code à partir du référentiel . Cela peut fonctionner sur votre machine avec vos fichiers ... que vous avez oublié de valider. Cela peut dépendre d'une nouvelle table qui ne contient pas le script de création (dans Liquibase par exemple), des données de configuration ou des fichiers de propriétés.
  • Vous évitez les problèmes d'intégration de code. Un développeur télécharge la dernière version, crée des tests unitaires et d’intégration, ajoute du code, passe tous les tests sur sa machine, s’engage et effectue un push. Un autre développeur vient de faire la même chose. Les deux modifications sont exactes mais, lorsqu'elles sont fusionnées, elles provoquent un bogue. Cela peut être la fusion du référentiel ou simplement le fait que cela ne soit pas détecté comme un conflit. Par exemple, Dev 1 supprime le fichier qui n'a pas du tout été utilisé. Dev 2 code contre ce fichier et teste sans modifications de Dev 1.
  • Vous développez un script à déployer automatiquement à partir du référentiel. Avoir un script de construction et de déploiement universel résout beaucoup de problèmes. Certains développeurs peuvent avoir ajouté une option de compilation ou de compilation qui n'est pas partagée par tout le monde. Non seulement cela vous fait gagner du temps, mais surtout, cela rend le déploiement sûr et prévisible. De plus, vous pouvez revenir dans votre référentiel à la version 2.3.1 et déployer cette version avec un script qui fonctionne avec cette version. Il comprend des objets de base de données tels que les vues, les procédures stockées, les vues et les déclencheurs qui doivent être versionnés. (Ou vous ne pourrez pas revenir à une version exploitable).
  • Autres tests : comme les tests d' intégration, de performance et de bout en bout. Cela peut être lent et peut inclure des outils de test comme Selenium. Vous aurez peut-être besoin d'un ensemble complet de données avec une base de données réelle au lieu d'objets fictifs ou de HSQL.

Une fois, j'ai travaillé sur une entreprise qui présentait de nombreux problèmes de déploiement en raison du processus de fusion et de déploiement. Cela était dû à un cadre de propriété étrange qui rendait les tests et l'IC difficiles. Ce n’était pas une expérience heureuse de constater que le code qui fonctionnait parfaitement pour le développement n’arrivait pas directement en production.

Borjab
la source
Oui, il est très courant d'oublier de mettre en œuvre certains des changements. Je dirais que l'oubli de "svn ajouter" de nouveaux fichiers, et donc de ne pas les valider plus tard, est le moyen le plus populaire d'obtenir une construction automatique défaillante.
Sharptooth
22

Vous penseriez que non, mais les développeurs sont humains et oublient parfois.

En outre, les développeurs ne parviennent souvent pas à extraire le dernier code. Leurs derniers tests pourraient bien fonctionner, puis au moment de l’enregistrement, une autre personne commet un changement radical.

Vos tests peuvent également s'appuyer sur une ressource locale (non contrôlée). Quelque chose que vos tests d'unité locale n'auraient pas compris.

Si vous pensez que tout ce qui précède est fantaisiste, il existe un niveau supérieur à CI (sur TFS au moins) appelé Gated où les versions dont les tests ont échoué sont stockées et ne sont pas affectées à la base de code.

Robbie Dee
la source
7
J'ai vu plus de oups j'ai oublié de commettre ces échecs de CI que je tiens à admettre.
Dan Neely
@DanNeely Pour être honnête, il vaut mieux que le responsable de la construction lui donne un coup de pied parce que vous avez oublié de lui dire quelque chose ... :-)
Robbie Dee
3
C'est l'une des raisons pour lesquelles j'aime CI. Trouver et réparer vos propres yeux est bien mieux que d’avoir quelqu'un qui les trouve pour vous.
Dan Neely
14

au moment où quelque chose est engagé à maîtriser

En général, je configure mon CI pour s’exécuter sur chaque commit. Les branches ne sont pas fusionnées dans le maître tant que la branche n’a pas été testée. Si vous comptez exécuter des tests sur master, cela ouvre une fenêtre pour que la construction soit cassée.

L'exécution des tests sur une machine CI implique des résultats reproductibles. Étant donné que le serveur CI a un environnement propre connu extrait de votre VCS, vous savez que les résultats du test sont corrects. Lorsque vous exécutez localement, vous pouvez oublier de valider le code nécessaire à leur transmission ou disposer d'un code non engagé qui les fait passer alors qu'ils devraient échouer.

Cela permet également aux développeurs de gagner du temps en exécutant différentes suites en parallèle, en particulier s'il s'agit de tests lents de plusieurs minutes qui ne risquent pas de s'exécuter localement après chaque modification.

Dans mon travail actuel, notre déploiement de production est déclenché sur CI en passant tous les tests. Les scripts de déploiement empêcheront le déploiement à moins qu'ils ne passent. Cela rend impossible d'oublier accidentellement de les exécuter.

Le fait que CI fasse partie du flux de travail allège également le fardeau des développeurs. En tant que développeur, exécutez-vous habituellement un linter, un analyseur statique, un test unitaire, une couverture de code et un test d'intégration pour chaque modification? CI peut, de manière totalement automatique et sans avoir besoin d'y penser, ce qui réduit la fatigue des décisions.

Daenyth
la source
1
Vous ne devriez pas vraiment avoir de tests unitaires lents - cela viole les principes de FIRST .
Robbie Dee
4
@RobbieDee: Je pense qu'en général, le serveur CI exécute tous les tests, pas seulement les tests unitaires.
RemcoGerlich
4
@RobbieDee: en théorie, tous les tests unitaires sont rapides. En pratique ... Quoi qu’il en soit, CI peut et doit exécuter tous les tests - linters, analyse statique, tests unitaires, tests d’intégration.
Daenyth
2
@RobbieDee Évidemment, les détails de la configuration varieront d'une équipe à l'autre. Même lorsque les versions prennent plusieurs minutes, il est souvent possible d'exécuter plusieurs de ces versions en parallèle. Avec une seule base de code monolithique, cela pourrait être un inconvénient plus important, mais IME n’est pas un obstacle.
Daenyth
1
@RobbieDee Je pense que cela dépend plus de votre architecture. Je l'ai déjà vu fonctionner pour une équipe d'ingénieurs d'environ 80 personnes, mais avec des sous-équipes bien définies pour les domaines de produits.
Daenyth
4

Au moment de maîtriser quelque chose, un développeur devrait déjà avoir exécuté tous les tests unitaires ... mais que se passe-t-il s'ils ne le font pas? Si vous n'exécutez pas les tests unitaires sur le serveur CI, vous ne le saurez pas tant que quelqu'un n'aura pas modifié les modifications apportées à leur ordinateur et découvert les tests qui viennent de se produire.

De plus, le développeur peut avoir commis une erreur et référencé une ressource locale spécifique à sa machine. Lorsqu'ils archivent le code et que l'exécution du CI échoue, le problème est immédiatement identifié et peut être corrigé.

David Arno
la source
3

En supposant (contrairement à d’autres réponses) que les développeurs sont assez disciplinés et effectuent des tests unitaires avant de s’engager, il peut y avoir plusieurs raisons:

  • l'exécution de tests unitaires peut prendre beaucoup de temps pour une configuration spéciale. Par exemple, l'exécution de tests unitaires avec un vérificateur de mémoire (tel que valgrind) peut prendre beaucoup plus de temps. Bien que tous les tests unitaires réussissent, la vérification de la mémoire peut échouer.
  • le résultat n'est pas très important pour certains paramètres spéciaux - par exemple, l'exécution de tests unitaires pour vérifier la couverture de code nécessite des indicateurs de compilation spéciaux. Pour les développeurs normaux, la couverture de code n’est pas si importante que cela: c’est davantage pour les personnes attentives que le code conserve certaines qualités, comme les chefs d’équipe.
BЈовић
la source
3

Il est possible d'imaginer des cas où le changement A ne rompt pas le test et le changement B ne le rompt pas, mais A et B ensemble . Si A et B sont créés par des développeurs différents, seul le serveur CI détecte le nouveau bogue. A et B peuvent même être deux parties de la même phrase plus longue.

Imaginez un train conduit par les deux locomotives A et B. Peut-être qu’une seule suffirait et c’est la solution à appliquer. Cependant, si les deux "correctifs" sont appliqués en supprimant les deux, le train ne bougera pas.

En outre, tous les développeurs n'exécutent pas tous les tests unitaires, contrairement à la plupart des bons développeurs.

h22
la source
2

Posons une question équivalente:

Pourquoi voudriez-vous construire le code sur un serveur CI?

Sûrement, au moment où quelque chose se met à maîtriser, un développeur a déjà créé le code et corrigé toutes les erreurs pouvant survenir avec son nouveau code. N'est-ce pas le but du code du bâtiment? Sinon, ils viennent de commettre un code erroné.


Il y a plusieurs raisons pour faire de l'EC, mais son objectif principal est de se faire une idée de l'état du code dans le temps. Le principal avantage (parmi plusieurs) que cela procure est que nous pouvons savoir quand la construction commence, déterminer ce qui l’a brisé, puis le réparer.

Si le code n'est jamais cassé, pourquoi utilisons-nous même un CI? Pour fournir des versions à tester, des versions nocturnes seraient suffisantes.

Peter
la source