Un des principes fondamentaux de la conception de vos builds d'intégration continue est que la valeur de l'information d'un échec de build diminue rapidement avec le temps. En d'autres termes, plus le retour d'un échec de build met de temps à vous atteindre, moins il vaut la peine, et plus dur il est à corriger.
En effet, si vos tests fonctionnels ou d'intégration prennent plusieurs heures pour s'exécuter, il y a des chances qu'ils ne seront pas exécutés à chaque changement. Ils sont plus susceptibles d'être programmés comme un build quotidien. Le problème est alors que beaucoup de choses peuvent intervenir en vingt-quatre heures, et, si le build quotidien échoue, il sera difficile de déterminer lequel des nombreux changements committés sur le contrôle de version pendant la journée était responsable. C'est un problème sérieux, et pénalise la capacité de votre serveur d'intégration continue de fournir un retour rapide qui le rend utile.
Bien sûr, certains builds sont lents, par nature . Les tests de performance ou de charge rentrent dans cette catégorie, comme d'autres builds lourds de métriques de qualité de code pour de gros projets. Cependant, les tests d'intégration et fonctionnels ne rentrent pas dans cette catégorie. Vous devez faire tout ce que vous pouvez pour rendre ces tests aussi rapides que possible. Moins de dix minutes est probablement acceptable pour une suite complète d'intégration/fonctionnel. Deux heures ne l'est pas.
Donc, si vous vous trouvez vous-même à devoir accélérer vos tests, voici quelques stratégies qui seront utiles, par ordre approximatif de difficulté.
Quelquefois la façon la plus facile pour accélérer vos builds est de rajouter du matériel. Cela pourrait être aussi simple que de mettre à jour votre serveur de build. Comparé au temps et effort passés à identifier et corriger les bugs liés à l'intégration, le coût d'achat d'un nouveau serveur flambant neuf est relativement faible.
Une autre option est d'envisager l'utilisation d'approches virtuelles ou basées sur le cloud. Plus tard dans le livre, nous verrons comment vous pouvez utiliser des machines virtuelles VMWare ou une infrastructure cloud telles que Amazon Web Services (EC2) ou CloudBees pour augmenter votre capacité de build sur une base “à la demande”, sans avoir à investir dans de nouvelles machines permanentes.
Cette approche peut également impliquer la distribution de vos builds sur plusieurs serveurs. Bien que cela ne va pas en tant que tel accélérer vos tests, cela peut mener à un retour plus rapide si votre serveur de build est sous forte demande, et si vos tâches de build sont constamment en attente.
Dans de nombreuses applications, les tests d'intégration ou fonctionnels sont utilisés par défaut comme moyen standard pour tester presque tous les aspects du système. Cependant, les tests d'intégration et fonctionnels ne sont pas le meilleur moyen de détecter et d'identifier les bugs. En raison du grand nombre de composants impliqués dans un test typique de bout en bout, il peut être très difficile de savoir où s'est produit l'erreur. En outre, avec autant de pièces changeant, il est extrêmement difficile, si ce n'est totalement irréalisable, de couvrir l'ensemble des chemins possibles à travers l'application.
Pour cette raison, dans la mesure du possible, vous devriez préférer les tests unitaires rapides aux tests d'intégration et fonctionnels beaucoup plus lents. Quand vous êtes confiants dans le fait que les composants individuels fonctionnent correctement, vous pouvez compléter le tableau par quelques tests de bout en bout qui passent par des cas d'utilisation communs du système, ou des cas d'utilisation qui ont causé des problèmes par le passé. Cela va garantir que les composants s'emboîtent correctement, ce qui est, après tout, ce que les tests d'intégration sont supposés faire. Mais préférez, dans la mesure du possible, les tests unitaires aux tests plus complets. Cette stratégie est probablement l'approche la plus viable pour maintenir votre retour rapide, mais elle nécessite une certaine discipline et des efforts.
Si vos tests fonctionnels prennent deux heures pour s'exécuter, il est peu probable qu'ils aient tous besoin de s'exécuter à la suite. Il est aussi peu probable qu'ils consomment toute la CPU disponible sur votre machine de build. Alors découper vos tests d'intégration en petits lots et les exécuter en parallèle a beaucoup de sens.
Il y a plusieurs stratégies que vous pouvez essayer, et votre choix va probablement dépendre de la nature de votre application. Une approche, par exemple, est de mettre en place plusieurs tâches de build pour exécuter des sous ensembles différents de vos tests fonctionnels, et de lancer ces tâches en parallèle. Jenkins vous permet d'agréger les résultats de test. C'est une bonne façon de tirer avantage de l'architecture de build distribuée pour accélérer vos builds encore plus. Le point essentiel de cette stratégie est la capacité d'exécuter des sous-ensembles de vos tests en isolation, ce qui peut demander une certaine restructuration.
A un plus bas niveau, vous pouvez aussi exécuter vos tests en parallèle au niveau des scripts de build. Comme nous avons vu précédemment, TestNG et les versions les plus récentes de JUnit supportent tous les deux l'exécution de tests en parallèle. Néanmoins, vous devrez vous assurer que vos tests peuvent être exécutés simultanément, ce qui peut nécessiter une restructuration. Par exemple, les fichiers communs ou des variables d'instance partagées vont dans ce cas causer des problèmes.
En général, vous devez être prudent sur les interactions entre vos tests. Si vos tests web démarrent un serveur Web intégré, comme Jetty, par exemple, vous devez vous assurer que le port utilisé est différent pour chaque ensemble de tests simultanés.
Néanmoins, si vous pouvez le faire fonctionner pour votre application, exécuter vos tests en parallèle est un des moyens les plus efficaces pour accélérer vos tests.