Let’s make this test suite run faster! SoftShake 2010

Qui n’a jamais attendu de nombreuses minutes pour builder un projet ? Et qui n’en a jamais profité pour aller boire un café/regarder twitter/… ? :) Parce que l’on teste fréquemment, il est important d’essayer d’optimiser et de réduire la durée d’exécution des tests.  Tester souvent ne veux pas dire attendre souvent ! Il est donc primordial d’essayer de réduire cette durée en jouant sur différents paramètres. Comment obtenir le résultat des tests le plus rapidement possible ?

Ce qui suit est tiré de la conférence de David Gageot [ @dgageot / http://javabien.net ] à SoftShake 2010.

Sur une vingtaine de personnes présentes dans la salle, les durées de build vont de quelques minutes à plusieurs heures. David présente brièvement quelques frameworks comme Infinitest et JUnitMax. Ce sont des plugins pour IDE Java qui permettent de lancer les tests unitaires en continu et de manière intelligente, c’est à dire uniquement ceux impactés par le code modifié.
La première idée lorsque l’on cherche à optimiser cette durée d’exécution, c’est de vouloir déléguer le problème. C’est faire  tourner les tests sur des serveurs distribués qui permettront d’exécuter les tests en tâches de fond. C’est une mauvaise idée, les serveurs coûtent chers et on peut se retrouver submerger. Il existe des méthodes plus simples pour réduire cette durée.

Le KISS ( Keep It Simple, Stupid ) est également applicable lorsque l’on crée des tests. Chercher à optimises ses tests peut améliorer votre produit : ce qui est simple à tester sera simple à coder et à utiliser. Ce qui est compliqué n’en vaut surement pas la peine.

Le tricheur

La manière la plus simple pour accélérer les tests c’est d’acheter une machine plus rapide. Exécuter les tests sur une machine plus rapide peut être un vrai gain de temps, David nous donne l’exemple d’une exécution 15% plus rapide sur la machine la plus rapide par rapport à la plus lente. Il est également possible d’utiliser la nouvelle fonctionnalité de maven de build en parallèle (mvn -T2 clean install / mvn -t4 clean install). Nous avons essayé sur un de nos projets, l’exécution du build est passé de 1m30 à 30 secondes !
Il est également possible de faire en sorte que les tâches maven surefire pour JUnit et TestNG soient exécutés en parallèle. Comme les tests se doivent d’être indépendant et isolés, ce sont de bons candidats à une exécution en parallèle. Faire quand même attention que vous pouvez vous retrouver avec des problèmes de concurrence dans certains cas.

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <version>2.5</version>
   <configuration>
     <parallel>methods</parallel>
     <threadCount>4</threadCount>
   </configuration>
</plugin>

Il existe deux façons de paralléliser : méthodes ou classes. Utiliser la méthode de parallélisation par méthode peut se révéler risqué car il est fort probable que tous les tests n’auront pas été designés dans l’optique d’être exécutés en parallèle, la méthode ‘classes’ est un choix plus prudent. Plus d’infos sur le blog de Wakaleo Consulting.

Le paresseux

Il y a souvent des tests redondants dans un projets : débusquez les, cela permettra de gagner en exécution et en lisibilité. C’est tellement simple qu’on ne le fait pas ! Ne pas hésiter à supprimer des fonctionnalités et les tests associés si elles ne servent plus rien, le projet y gagnera en simplicité.
Les accès réseaux et disques sont trop lents. Il faut essayer au maximum de s’en passer et privilégier les bases de données en mémoire comme h2 (qui ressemblera plus à mysql que hsqldb). De même pour les accès mails, il est possible d’utiliser dans les tests des serveurs SMTP en mémoire comme ethereal. Si beaucoup de tests accèdent à des fichiers, Spring Resource ou Apache VFS (Virtual File System) sont de bonnes alternatives.

Le brave

Il est préférable de tester les règles métiers dans les tests unitaires plutôt que dans les test d’intégrations. Il ne faut pas confondre tests d’intégrations et tests unitaires : les premiers sont , bien qu’essentiel, plus longs à tester, ils doivent être utiliser avec parcimonie. Par exemple, pour plusieurs tests qui accèderaient à une base de données peuvent être remplacés par un test qui permet de garantir que l’on peut bien accéder à la base de données et par plusieurs autres tests où l’accès à la base de données aura été bouchonné.
Une méthode lorsque l’on cherche à diminuer la durée d’exécution de tests est de prendre le test d’intégration le plus long et de l’analyser jusqu’à réussir à le découper en un test d’intégration plus petit et plusieurs tests unitaires. Si c’est l’accès à certaines couches qui sont lentes lors de tests d’intégrations, il est recommandé de les bouchonner, les frameworks de mocks ne servent pas que dans le cas de tests unitaires :)
De même, méfiez vous des tests d’interface, ils prennent beaucoup de temps et souvent, ce qu’ils testent peut être tester unitairement. Selenium est à utiliser avec modération. Méfiez vous vraiment quand vous commencez à tester vos fonctionnalités via Selenium. Et ne dites pas ‘mon utilisateur veut de l’AJAX‘ ‘J’ai besoin de tester la compatibilité des différents navigateurs’.

Chaque complexité a un coût. Et cela se paye à chaque fois que les tests sont exécutés.  Si c’est compliqué à tester : danger, la fonctionnalité peut sûrement être faite plus simplement. Il est possible de faire des tests unitaires en Javascript plutôt que tester dans les browsers (ex : QUnit).
David préfère limité AJAX aux réels besoins et d’effectuer au maximum le code server-side.

Et pour finir : simplifier et optimiser votre code. Ce sont des choses qui se font. Le build va être plus rapide et l’application aussi 😀 A vous l’effet Kiss Cool :)

4 Responses to “Let’s make this test suite run faster! SoftShake 2010”

  1. Sylvain V. dit :

    « serveurs SMTP en mémoire comme ethereal »

    Le principe m’intéresse, mais je ne vois pas de quoi il s’agit… Pour moi ethereal, c’est l’ancien nom de Wireshark, le maintenant vénérable (et indispensable) analyseur réseau.

  2. louis gueye dit :

    Article agréable Mathilde, je t’ai trouvée très inspirée …

    Je suis d’accord avec toi, l’apport du dual/quadri core de la machine est indéniable mais c’est quand même tricher.
    Le mieux (mais plus couteux car prend plus de temps) c’est de designer correctement, côté serveur de préférence car il y a plus d’assurance qualité côté serveur.

    Je te rejoins aussi sur le fait qu’il est plus intéressant de tester le résultat d’un événement (état d’un objet backend, cinématique) que l’interface graphique elle même. Ce sont des choses testables unitairement si votre le framework de développement est bien écrit (swing pour le client lourd, spring mvc ou autre pour le web).

  3. Mathilde Lemée dit :

    SubEthaSMTP plutôt !

    Merci Louis :p

  4. J’utilise GreenMail (http://www.icegreen.com/greenmail) pour tester l’envoi de Mail, existe aussi un greenmail-spring pour une meilleur intégration avec Spring.

    Olivier.

Leave a Reply