lundi 9 janvier 2012

Mettre ses tests unitaires dans chaque script PHP

Concernant les tests unitaires pour une application web développée en PHP.

Après avoir testé plusieurs solutions pendant plusieurs années, j'ai abandonné. Pourtant j'y ai mis du mien : PHPUnit 2 et 3, Simple Test. Globalement, je reproche à ces outils de demander un travail à fournir trop important par rapport à celui nécessaire pour fabriquer l'application elle-même. Il ne faut pas oublier que beaucoup de concept de PHP servent à simplifier le travail et raccourcir le temps de développement.


Mais,

Il y a quelques mois, j'ai découvert Test::More et j'ai trouvé que cela correspondait parfaitement aux besoins de PHP. Après quelques essais, je me retrouve avec ma propre implémentation de Test::More en PHP (-800 lignes avec commentaires) et depuis mes projets ont une nouvelle vie.

Avec un peu de bidouille (-200 lignes) je suis capable de :
  • stocker les tests unitaires au même endroit que le code.
  • de lancer les tests en lançant le script lui même.
  • de coder les tests en même temps que les fonctionnalités.
  • de lancer tous les tests et de faire un rapport.
Voici un petit exemple d'un script qui déclare des choses et qui fait les tests :

<?php

// Unittests launcher
if( ! define('test') )
{
  define('test',__FILE__);
  require_once(__DIR__.'/../config.php');
  app\unit\test(__FILE__,__COMPILER_HALT_OFFSET__,__NAMESPACE__);
}

// [...] classes, functions or features to tests

__halt_compiler();

// Test 1
test\plan(1);
test\ok(true);

----

// Test 2
test\plan(1);
require_once __FILE__;
test\ok( /* Call a function or whatever */ );

Évidemment, il n'y a pas de if __name__ == "__main__" en PHP. Il faut donc une bidouille en haut du script.
En utilisant la fonction __halt_compiler() et la constante __COMPILER_HALT_OFFSET__ on peux facilement stocker du code dans le script. L'intérêt est que cette fonction n'arrête pas l'exécution de tous les scripts, mais uniquement le courant.
Dans cette exemple, je me sers de la balise ---- comme séparateur de test et la fonction app\unit\test() va prendre le code entre chaque balise ---- trouvée est créer des fichiers séparés, lancés ... séparément. Il y a donc un contexte différent pour chaque test.

L'autre intérêt est l'utilisation de Test::More qui rend les tests vraiment, vraiment cours.

Inconvénient : il faut tout faire soi-même.

Aucun commentaire:

Enregistrer un commentaire