La commande, toujours sur notre exemple simple, est : > phpunit --skeleton Addition On obtient une classe AdditionTest que voici : Exemple 5.3 exemples/AdditionTest.php:La classe de test
Trang 1218 Chapitre 5 Organisation du développement
nous le comportement de la méthode testée À titre d’exemple, changez le + en -dans notre méthode d’addition, puis effectuez à nouveau le test Voici ce que l’on obtient :
> phpunit PremierTest
PHPUnit 3.3.1 by Sebastian Bergmann.
F
Time: 0 seconds
There was 1 failure:
1) testAjout(PremierTest)
Failed asserting that <integer:0> matches expected value <integer:2> /Applications/MAMP/htdocs/exemples/PremierTest.php:14
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
Un des tests sur la méthode ajout() a échoué (celui qui effectue le contrôle
2 = 1 + 1), l’autre a réussi (celui qui vérifie que 3= 2 + 2) Il existe bien entendu de
très nombreuses autres assertions que vous pouvez découvrir dans la documentation
de PHPUnit
Effectuer des tests implique d’instancier la classe à tester, puis d’appliquer des méthodes sur l’objet obtenu Pour éviter l’aspect répétitif de ce mécanisme, PHPUnit fournit un générateur de « squelette » d’une classe de test La commande, toujours sur notre exemple simple, est :
> phpunit skeleton Addition
On obtient une classe AdditionTest que voici :
Exemple 5.3 exemples/AdditionTest.php:La classe de test engendrée automatiquement par PHPUnit
<? php
r e q u i r e _ o n c e ’ PHPUnit / Framework php ’ ;
r e q u i r e _ o n c e ’ A d d i t i o n php ’ ;
/∗ ∗
∗ T e s t c l a s s f o r A d d i t i o n
∗ G e n e r a t e d by PHPUnit on 2008−10−19 a t 1 7 : 3 6 : 4 5
∗ /
c l a s s A d d i t i o n T e s t e x t e n d s PHPUnit_Framework_TestCase
{
/∗ ∗
∗ @var A d d i t i o n
∗ @ a c c e s s p r o t e c t e d
Trang 2∗ /
p r o t e c t e d $ o b j e c t ;
/ ∗ ∗
∗ S e t s up t h e f i x t u r e , f o r example , o p e n s a n e t w o r k
c o n n e c t i o n
∗ T h i s method i s c a l l e d b e f o r e a t e s t i s e x e c u t e d
∗
∗ @ a c c e s s p r o t e c t e d
∗ /
p r o t e c t e d f u n c t i o n s e t U p ( )
{
$ t h i s−>o b j e c t = new Addition ;
}
/ ∗ ∗
∗ T e a r s down t h e f i x t u r e , f o r example , c l o s e s a n e t w o r k
c o n n e c t i o n
∗ T h i s method i s c a l l e d a f t e r a t e s t i s e x e c u t e d
∗
∗ @ a c c e s s p r o t e c t e d
∗ /
p r o t e c t e d f u n c t i o n tearDown ( )
{
}
/ ∗ ∗
∗ @todo I m p l e m e n t t e s t A j o u t ( )
∗ /
p u b l i c f u n c t i o n t e s t A j o u t ( ) {
/ / Remove t h e f o l l o w i n g l i n e s when y o u i m p l e m e n t t h i s
t e s t
$ t h i s−>markTestIncomplete (
’ T h i s t e s t h a s n o t been i m p l e m e n t e d y e t ’ ) ;
}
}
? >
Deux méthodes spéciales, setUp() et tearDown() ont été créées pour, respecti-vement, instancier un objet de la classe Addition et libérer cet environnement de test C’est à nous de compléter ces deux méthodes pour initialiser l’environnement
de test (par exemple on pourrait se connecter à la base de données avant d’effectuer des tests sur une application PHP/MySQL) Ensuite PHPUnit crée une méthode
testnomM´ eth () pour chaque méthode nomM´ eth de la classe testée Ici nous avons
donc une méthode testAjout() Toutes ces méthodes de test sont à implanter, comme le montre le @todo placé dans le DocBlock
Quand ce travail est réalisé pour toutes les classes et fonctions d’une
application, on peut regrouper les tests dans des suites grâce à la classe
Trang 3220 Chapitre 5 Organisation du développement
PHPUnit_FrameworkTestSuite Voici un exemple simple montrant comment intégrer notre classe de tests dans une suite
Exemple 5.4 exemples/MesTests.php:Création d’une suite de tests
<? php
/∗ ∗
∗ E n s e m b l e d e s t e s t s de l ’ a p p l i c a t i o n
∗ /
r e q u i r e _ o n c e ’ PHPUnit / Framework php ’ ;
r e q u i r e _ o n c e ’ PHPUnit / TextUI / T e s t R u n n e r php ’ ;
/∗ ∗ I n c l u s i o n d e s c l a s s e s à t e s t e r
∗
∗ /
r e q u i r e _ o n c e ’ A d d i t i o n T e s t php ’ ;
c l a s s M e s T e s t s
{
p u b l i c s t a t i c f u n c t i o n main ( )
{
PHPUnit_TextUI_TestRunner : : r u n ( s e l f : : s u i t e ( ) ) ;
}
p u b l i c s t a t i c f u n c t i o n s u i t e ( )
{
$ s u i t e = new P H P U n i t _ F r a m e w o r k _ T e s t S u i t e ( ’ Tous mes t e s t s ’ ) ;
$ s u i t e−>a d d T e s t S u i t e ( " A ddit ionTe s t " ) ;
r e t u r n $ s u i t e ;
}
}
? >
On peut ensuite exécuter une suite de tests avec phpunit Arrêtons là pour cette
brève introduction dont le but est esentiellement de vous donner une idée du processus de constitution de tests automatiques pour valider une application Une fois ces tests mis en place – ce qui peut évidemment prendre beaucoup de temps – on peut les ré-exécuter à chaque nouvelle version de l’application pour vérifier qu’il n’y
a pas de régression
5.1.5 En résumé
Ce qui précède a montré une partie des outils qui constituent un environnement de haut niveau pour la production et la maintenance d’applications web On pourrait
encore citer Phing, un descripteur de tâches comparable au make Unix, pour
enchaî-ner automatiquement des étapes de construction (vérification syntaxique, tests,
Trang 4documentation, etc.) d’une application livrable, Xdebug pour déverminer («
débu-guer » ) ou profiler des applications, etc
Encore une fois l’utilisation de ces outils est à apprécier en fonction du contexte
Eclipse est vraiment un must : cet IDE rend de tels services qu’il est vraiment difficile
de s’en passer une fois qu’on y a gỏté Les tests et la documentation constituent quant à eux des efforts importants qui s’imposent principalement dans les processus
de production de code de haute qualité, en vue par exemple d’une certification
5.2 GESTION DES ERREURS
Même si l’on a mis en place une procédure de tests automatisée avec PHPUnit,
il faut toujours envisager qu’une erreur survienne pendant le déroulement d’une application La gestion des erreurs est un problème récurrent Il faut se poser en permanence la question des points faibles du code et des conséquences possibles d’un fonctionnement incorrect ou de données non conformes à ce qui est attendu Cette vigilance est motivée par trois préoccupations constantes :
1 avertir correctement l’utilisateur du problème et des solutions pour le résoudre ;
2 ne pas laisser l’application poursuivre son exécution dans un contexte cor-rompu ;
3 être prévenu rapidement et précisément de la cause de l’erreur afin de pouvoir
la corriger
Il faut également s’entendre sur le sens du mot « erreur » Nous allons en distin-guer trois types : erreurs d’utilisation, erreurs syntaxiques et erreurs internes
Erreurs d’utilisation
Dans le contexte d’applications web, de nature fortement interactives, beaucoup
« d’erreurs » résultent de données ou d’actions imprévues de la part de l’utilisateur
Ce dernier n’est pas en cause, puisqu’on peut très bien considérer que l’interface devrait interdire ces saisie ou actions Il n’en reste pas moins que ces erreurs se caractérisent par la nécessité de fournir un retour indiquant pourquoi l’appel à telle
ou telle fonctionnalité a été refusé ou a échoué
Nous avons déjà étudié la question du contrơle des données en entrée d’un script (voir page 70) et la production de messages en retour Toute erreur d’utilisation implique une communication avec l’utilisateur, laquelle prend dans la majorité des cas la forme d’un message à l’écran
Erreurs internes
Les erreurs internes les plus communes sont dues à la manipulation de données anormales (comme une division par zéro) ou à la défaillance d’un des composants
de l’application (le serveur de base de données par exemple) Ce qui caractérise
Trang 5222 Chapitre 5 Organisation du développement
une erreur interne, c’est l’apparition d’une configuration dans laquelle l’application
ne peut plus fonctionner correctement Ces configurations ne sont pas toujours détectables durant la phase de test, car elles dépendent parfois d’événements qui apparaissent de manière imprévisible Une bonne application devrait être capable de réagir correctement à ce type d’erreur
Erreurs syntaxiques
Enfin, les erreurs syntaxiques sont dues à une faute de programmation, par exemple l’appel à une fonction avec de mauvais paramètres, ou toute instruction incor-recte empêchant l’interprétation du script En principe, elles devraient être élimi-nées au moment des tests Si ceux-ci ne sont pas menés systématiquement, cer-taines parties du code peuvent ne jamais être testées avant le passage en produc-tion
L’approche PHP
La section qui suit présente les principales techniques de traitement d’erreur en PHP
Les erreurs d’utilisation ne sont pas spécifiquement considérées puisque nous avons
déjà vu de nombreux exemples, et qu’il n’y a pas grand chose d’autre à faire que
de tester systématiquement les entrées d’un script ou d’une fonction, et de produire
un message si quelque chose d’anormal est détecté L’utilisation des exceptions PHP n’est pas pratique dans ce cas, car un lancer d’exception déroute le flux d’exécution du script vers la prochaine instruction catch, ce qui n’est souvent pas souhaitable pour
ce type d’erreur Les erreurs syntaxiques doivent être éliminées le plus vite possible La
première sous-section ci-dessous montre comment mettre en œuvre dès la phase de développement un contrôle très strict des fautes de programmation
Enfin les erreurs internes peuvent être interceptées et traitées, en PHP 5, par l’un
ou l’autre des deux moyens suivants :
1 les erreurs PHP ;
2 les exceptions.
Pour chacun il est possible de définir des gestionnaires d’erreur spécialisés, que l’on pourra donc régler différemment sur un site de développement ou sur un site de production
5.2.1 Erreurs syntaxiques
Les fautes de programmation sont en principe détectables au moment des tests, si ceux-ci sont menés de manière suffisamment exhaustive PHP est un langage assez permissif, qui autorise une programmation assez relâchée Cela permet un dévelop-pement très rapide et assez confortable, mais en contrepartie cela peut dans certains cas rendre le comportement du script erroné
En PHP les variables ne sont pas déclarées, sont typées en fonction du contexte,
et peuvent même, si l’installation est configurée assez souplement, ne pas être