Blog technique Wizaplace

PHPUnit-slicer : parallélisez vos tests PHPUnit

Par Vincent le 13 February 2018

Nous avons récemment été confrontés à un problème bloquant au sein de l’équipe technique : la durée de la suite de tests.

Mais avant de parler des détails, plantons le décor :

Nous utilisons Drone CI pour faire tourner nos tests, que nous hébergeons sur 2 serveurs dédiés. Chaque git push lance plusieurs jobs:

  • Une suite Atoum qui tourne en mode parallèle (de simples tests unitaires sans accès DB / autres)
  • Une suite Atoum en mode séquentiel (des tests plus avancés, qui utilisent la DB)
  • Une suite PHPUnit qui devient assez lourde car elle accueille tous les tests écrits depuis plus d’un an
  • Plusieurs suites Behat pour vérifier la partie front

Notre équipe s’agrandissant, la suite PHPUnit devient très lourde et cela se ressent sur le temps pour faire tourner un commit, et donc la file d’attente est de plus en plus engorgée.

C’est alors que Guillaume a eu une idée :

Hé, et si on coupait la suite PHPUnit en deux ? Du genre on fait tourner les tests dans les dossiers A-M et dans un autre job les tests de N à Z ?

Une PR de ce style a alors vu le jour :

PR

Étant donné que nous avons beaucoup de tests API (qui commencent par la lettre A donc), la coupure est faite après le E, pour avoir un résultat aproximativement 50/50.

Vient alors ma réaction quand j’ai ouvert la PR :

WTF

Il fallait que l’on trouve une vraie solution. C’est là que j’ai eu l’idée de faire un plugin PHPUnit pour faire le découpage exactement au milieu, peu importe le nombre de tests.

Je me suis beaucoup inspiré du plugin phpunit-randomizer pour arriver à quelque chose de fonctionnel, car je n’avais aucune idée de comment étendre PHPUnit.

Après quelques heures de travail, phpunit-slicer est né ! Grosso modo, il consiste en un array_slice sur le tableau contenant tous les tests, avant de les éxecuter. Par exemple, pour découper la suite de test en 2 on remplace le job vendor/bin/phpunit par :

  • vendor/bin/phpunit-slicer --slices 1/2
  • vendor/bin/phpunit-slicer --slices 2/2

On peut désormais jouer tous nos tests PHPUnit dans 2 jobs ! Et si demain l’on juge que c’est devenu trop long, suite à l’ajout de nouveaux tests : il suffit de faire 3 jobs !

Voici un avant/après :

Avant :

Avant

Après (job 1) :

Après 1/2

Après (job 2) :

Après 2/2

On passe donc de 8.17 minutes à 4.41 minutes (étant donné que les jobs tournent en parallèle, on ignore le temps le plus petit).