123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>
- Prise en main rapide de SimpleTest pour PHP -
- Tests unitaire et objets fantaisie pour PHP
- </title>
- <link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
- </head>
- <body>
- <div class="menu_back"><div class="menu">
- <a href="index.html">SimpleTest</a>
- |
- <a href="overview.html">Overview</a>
- |
- <a href="unit_test_documentation.html">Unit tester</a>
- |
- <a href="group_test_documentation.html">Group tests</a>
- |
- <a href="mock_objects_documentation.html">Mock objects</a>
- |
- <a href="partial_mocks_documentation.html">Partial mocks</a>
- |
- <a href="reporter_documentation.html">Reporting</a>
- |
- <a href="expectation_documentation.html">Expectations</a>
- |
- <a href="web_tester_documentation.html">Web tester</a>
- |
- <a href="form_testing_documentation.html">Testing forms</a>
- |
- <a href="authentication_documentation.html">Authentication</a>
- |
- <a href="browser_documentation.html">Scriptable browser</a>
- </div></div>
- <h1>Prise en main rapide de SimpleTest</h1>
- This page...
- <ul>
- <li>
- <a href="#unit">Utiliser le testeur rapidement</a>
- avec un exemple.
- </li>
- <li>
- <a href="#group">Groupes de tests</a>
- pour tester en un seul clic.
- </li>
- <li>
- <a href="#mock">Utiliser les objets fantaisie</a>
- pour faciliter les tests et gagner en contrôle.
- </li>
- <li>
- <a href="#web">Tester des pages web</a>
- au niveau de l'HTML.
- </li>
- </ul>
- <div class="content">
-
- <p>
- Le présent article présuppose que vous soyez familier avec
- le concept de tests unitaires ainsi que celui de développement
- web avec le langage PHP. Il s'agit d'un guide pour le nouvel
- et impatient utilisateur de
- <a href="https://sourceforge.net/project/showfiles.php?group_id=76550">SimpleTest</a>.
- Pour une documentation plus complète, particulièrement si
- vous découvrez les tests unitaires, consultez la
- <a href="http://www.lastcraft.com/unit_test_documentation.php">documentation
- en cours</a>, et pour des exemples de scénarios de test,
- consultez le
- <a href="http://www.lastcraft.com/first_test_tutorial.php">tutorial
- sur les tests unitaires</a>.
- </p>
-
- <h2>
- <a class="target" name="unit"></a>Utiliser le testeur rapidement</h2>
- <p>
- Parmi les outils de test pour logiciel, le testeur unitaire
- est le plus proche du développeur. Dans un contexte de
- développement agile, le code de test se place juste à côté
- du code source étant donné que tous les deux sont écrits
- simultanément. Dans ce contexte, SimpleTest aspire à être
- une solution complète de test pour un développeur PHP et
- s'appelle "Simple" parce qu'elle devrait être simple à
- utiliser et à étendre. Ce nom n'était pas vraiment un bon
- choix. Non seulement cette solution inclut toutes les
- fonctions classiques qu'on est en droit d'attendre de la
- part des portages de <a href="http://www.junit.org/">JUnit</a> et des <a href="http://sourceforge.net/projects/phpunit/">PHPUnit</a>,
- mais elle inclut aussi les <a href="http://www.mockobjects.com/">objets fantaisie ou
- "mock objects"</a>.
- </p>
- <p>
- Ce qui rend cet outil immédiatement utile pour un développeur PHP,
- c'est son navigateur web interne.
- Il permet des tests qui parcourent des sites web, remplissent
- des formulaires et testent le contenu des pages.
- Etre capable d'écrire ces tests en PHP veut dire qu'il devient
- facile d'écrire des tests de recette (ou d'intégration).
- Un exemple serait de confirmer qu'un utilisateur a bien été ajouté
- dans une base de données après s'être enregistré sur une site web.
- </p>
- <p>
- La démonstration la plus rapide : l'exemple
- </p>
- <p>
- Supposons que nous sommes en train de tester une simple
- classe de log dans un fichier : elle s'appelle
- <span class="new_code">Log</span> dans <em>classes/Log.php</em>. Commençons
- par créer un script de test, appelé
- <em>tests/log_test.php</em>. Son contenu est le suivant...
- <pre>
- <?php
- <strong>require_once('simpletest/autorun.php');</strong>
- require_once('../classes/log.php');
- class TestOfLogging extends <strong>UnitTestCase</strong> {
- }
- ?>
- </pre>
- Ici le répertoire <em>simpletest</em> est soit dans le
- dossier courant, soit dans les dossiers pour fichiers
- inclus. Vous auriez à éditer ces arborescences suivant
- l'endroit où vous avez installé SimpleTest.
- Le fichier "autorun.php" fait plus que juste inclure
- les éléments de SimpleTest : il lance aussi les tests pour nous.
- </p>
- <p>
- <span class="new_code">TestOfLogging</span> est notre premier scénario de test
- et il est pour l'instant vide.
- Chaque scénario de test est une classe qui étend une des classes
- de base de SimpleTest. Nous pouvons avoir autant de classes de ce type
- que nous voulons.
- </p>
- <p>
- Avec ces trois lignes d'échafaudage
- l'inclusion de notre classe <span class="new_code">Log</span>, nous avons une suite
- de tests. Mais pas encore de test !
- </p>
- <p>
- Pour notre premier test, supposons que la classe <span class="new_code">Log</span>
- prenne le nom du fichier à écrire au sein du constructeur,
- et que nous avons un répertoire temporaire dans lequel placer
- ce fichier.
- <pre>
- <?php
- require_once('simpletest/autorun.php');
- require_once('../classes/log.php');
- class TestOfLogging extends UnitTestCase {
- function <strong>testLogCreatesNewFileOnFirstMessage()</strong> {
- @unlink('/temp/test.log');
- $log = new Log('/temp/test.log');
- <strong>$this->assertFalse(file_exists('/temp/test.log'));</strong>
- $log->message('Should write this to a file');
- <strong>$this->assertTrue(file_exists('/temp/test.log'));</strong>
- }
- }
- ?>
- </pre>
- Au lancement du scénario de test, toutes les méthodes qui
- commencent avec la chaîne <span class="new_code">test</span> sont
- identifiées puis exécutées.
- Si la méthode commence par <span class="new_code">test</span>, c'est un test.
- Remarquez bien le nom très long de notre exemple :
- <span class="new_code">testLogCreatesNewFileOnFirstMessage()</span>.
- C'est bel et bien délibéré : ce style est considéré désirable
- et il rend la sortie du test plus lisible.
- </p>
- <p>
- D'ordinaire nous avons bien plusieurs méthodes de tests.
- Mais ce sera pour plus tard.
- </p>
- <p>
- Les assertions dans les
- méthodes de test envoient des messages vers le framework de
- test qui affiche immédiatement le résultat. Cette réponse
- immédiate est importante, non seulement lors d'un crash
- causé par le code, mais aussi de manière à rapprocher
- l'affichage de l'erreur au plus près du scénario de test
- concerné via un appel à <span class="new_code">print</span>code>.
- </p>
- <p>
- Pour voir ces résultats lançons effectivement les tests.
- Aucun autre code n'est nécessaire, il suffit d'ouvrir
- la page dans un navigateur.
- </p>
- <p>
- En cas échec, l'affichage ressemble à...
- <div class="demo">
- <h1>TestOfLogging</h1>
- <span class="fail">Fail</span>: testcreatingnewfile->True assertion failed.<br>
- <div style="padding: 8px; margin-top: 1em; background-color: red; color: white;">1/1 test cases complete.
- <strong>1</strong> passes and <strong>1</strong> fails.</div>
- </div>
- ...et si ça passe, on obtient...
- <div class="demo">
- <h1>TestOfLogging</h1>
- <div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1 test cases complete.
- <strong>2</strong> passes and <strong>0</strong> fails.</div>
- </div>
- Et si vous obtenez ça...
- <div class="demo">
- <b>Fatal error</b>: Failed opening required '../classes/log.php' (include_path='') in <b>/home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php</b> on line <b>7</b>
- </div>
- c'est qu'il vous manque le fichier <em>classes/Log.php</em>
- qui pourrait ressembler à :
- <pre>
- <?php<strong>
- class Log {
- function Log($file_path) {
- }
- function message() {
- }
- }</strong>
- ?>
- </pre>
- C'est largement plus sympathique d'écrire le code après le test.
- Plus que sympatique même - cette technique s'appelle
- "Développement Piloté par les Tests" ou
- "Test Driven Development" en anglais.
- </p>
- <p>
- Pour plus de renseignements sur le testeur, voyez la
- <a href="unit_test_documentation.html">documentation pour les tests de régression</a>.
- </p>
-
- <h2>
- <a class="target" name="group"></a>Construire des groupes de tests</h2>
- <p>
- Il est peu probable que dans une véritable application on
- ait uniquement besoin de passer un seul scénario de test.
- Cela veut dire que nous avons besoin de grouper les
- scénarios dans un script de test qui peut, si nécessaire,
- lancer tous les tests de l'application.
- </p>
- <p>
- Notre première étape est de créer un nouveau fichier appelé
- <em>tests/all_tests.php</em> et d'y inclure le code suivant...
- <pre>
- <?php
- <strong>require_once('simpletest/autorun.php');</strong>
- class AllTests extends <strong>TestSuite</strong> {
- function AllTests() {
- $this->TestSuite(<strong>'All tests'</strong>);
- <strong>$this->addFile('log_test.php');</strong>
- }
- }
- ?>
- </pre>
- L'inclusion de "autorun" permettra à notre future suite
- de tests d'être lancée juste en invoquant ce script.
- </p>
- <p>
- La sous-classe <span class="new_code">TestSuite</span> doit chaîner
- son constructeur. Cette limitation sera supprimée dans
- les versions à venir.
- </p>
- <p>
- The method <span class="new_code">TestSuite::addFile()</span>
- will include the test case file and read any new classes
- that are descended from <span class="new_code">SimpleTestCase</span>.
- Cette méthode <span class="new_code">TestSuite::addTestFile()</span> va
- inclure le fichier de scénarios de test et lire parmi
- toutes les nouvelles classes créées celles qui sont issues
- de <span class="new_code">SimpleTestCase</span>.
- <span class="new_code">UnitTestCase</span> est juste un exemple de classe dérivée
- depuis <span class="new_code">SimpleTestCase</span> et vous pouvez créer les vôtres.
- <span class="new_code">TestSuite::addFile()</span> peut aussi inclure d'autres suites.
- </p>
- <p>
- La classe ne sera pas encore instanciée.
- Quand la suite de tests est lancée, elle construira chaque instance
- une fois le test atteint, et le détuira juste ensuite.
- Cela veut dire que le constructeur n'est lancé qu'une fois avant
- chaque initialisation de ce scénario de test et que le destructeur
- est lui aussi lancé avant que le test suivant ne commence.
- </p>
- <p>
- Il est commun de grouper des scénarios de test dans des super-classes
- qui ne sont pas sensées être lancées, mais qui deviennent une classe de base
- pour d'autres tests.
- Pour que "autorun" fonctionne proprement les fichiers
- des scénarios de test ne devraient pas lancer aveuglement
- d'autres extensions de scénarios de test qui ne lanceraient pas
- effectivement des tests.
- Cela pourrait aboutir à un mauvais comptages des scénarios de test
- pendant la procédure.
- Pas vraiement un problème majeure, mais pour éviter cet inconvénient
- il suffit de marquer vos classes de base comme <span class="new_code">abstract</span>.
- SimpleTest ne lance pas les classes abstraites. Et si vous utilisez encore
- PHP4 alors une directive <span class="new_code">SimpleTestOptions::ignore()</span>
- dans votre fichier de scénario de test aura le même effet.
- </p>
- <p>
- Par ailleurs, le fichier avec le scénario de test ne devrait pas
- avoir été inclus ailleurs. Sinon aucun scénario de test
- ne sera inclus à ce groupe.
- Ceci pourrait se transformer en un problème plus grave :
- si des fichiers ont déjà été inclus par PHP alors la méthode
- <span class="new_code">TestSuite::addFile()</span> ne les détectera pas.
- </p>
- <p>
- Pour afficher les résultats, il est seulement nécessaire
- d'invoquer <em>tests/all_tests.php</em> à partir du serveur
- web.
- </p>
- <p>
- Pour plus de renseignements des groupes de tests, voyez le
- <a href="group_test_documentation.html">documentation sur le groupement des tests</a>.
- </p>
-
- <h2>
- <a class="target" name="mock"></a>Utiliser les objets fantaisie</h2>
- <p>
- Avançons un peu plus dans le futur.
- </p>
- <p>
- Supposons que notre class logging soit testée et terminée.
- Supposons aussi que nous testons une autre classe qui ait
- besoin d'écrire des messages de log, disons
- <span class="new_code">SessionPool</span>. Nous voulons tester une méthode
- qui ressemblera probablement à quelque chose comme...
- <pre><strong>
- class SessionPool {
- ...
- function logIn($username) {
- ...
- $this->_log->message('User $username logged in.');
- ...
- }
- ...
- }
- </strong>
- </pre>
- Avec le concept de "réutilisation de code" comme fil
- conducteur, nous utilisons notre class <span class="new_code">Log</span>. Un
- scénario de test classique ressemblera peut-être à...
- <pre>
- <?php
- require_once('simpletest/autorun.php');
- require_once('../classes/log.php');
- <strong>require_once('../classes/session_pool.php');</strong>
- class <strong>TestOfSessionLogging</strong> extends UnitTestCase {
-
- function setUp() {
- <strong>@unlink('/temp/test.log');</strong>
- }
-
- function tearDown() {
- <strong>@unlink('/temp/test.log');</strong>
- }
-
- function testLoggingInIsLogged() {
- <strong>$log = new Log('/temp/test.log');
- $session_pool = &new SessionPool($log);
- $session_pool->logIn('fred');</strong>
- $messages = file('/temp/test.log');
- $this->assertEqual($messages[0], "User fred logged in.<strong>\n</strong>");
- }
- }
- ?>
- </pre>
- Nous expliquerons les méthodes <span class="new_code">setUp()</span>
- et <span class="new_code">tearDown()</span> plus tard.
- </p>
- <p>
- Le design de ce scénario de test n'est pas complètement
- mauvais, mais on peut l'améliorer. Nous passons du temps à
- tripoter les fichiers de log qui ne font pas partie de
- notre test.
- Pire, nous avons créé des liens de proximité
- entre la classe <span class="new_code">Log</span> et ce test. Que se
- passerait-il si nous n'utilisions plus de fichiers, mais la
- bibliothèque <em>syslog</em> à la place ?
-
- Cela veut dire que notre test <span class="new_code">TestOfSessionLogging</span>
- enverra un échec alors même qu'il ne teste pas Logging.
- </p>
- <p>
- Il est aussi fragile sur des petites retouches. Avez-vous
- remarqué le retour chariot supplémentaire à la fin du
- message ? A-t-il été ajouté par le loggueur ? Et si il
- ajoutait aussi un timestamp ou d'autres données ?
- </p>
- <p>
- L'unique partie à tester réellement est l'envoi d'un
- message précis au loggueur.
- Nous pouvons réduire le couplage en
- créant une fausse classe de logging : elle ne fait
- qu'enregistrer le message pour le test, mais ne produit
- aucun résultat. Sauf qu'elle doit ressembler exactement à
- l'original.
- </p>
- <p>
- Si l'objet fantaisie n'écrit pas dans un fichier alors nous
- nous épargnons la suppression du fichier avant et après le
- test. Nous pourrions même nous épargner quelques lignes de
- code supplémentaires si l'objet fantaisie pouvait exécuter
- l'assertion.
- <p>
- </p>
- Trop beau pour être vrai ? Pas vraiement on peut créer un tel
- objet très facilement...
- <pre>
- <?php
- require_once('simpletest/autorun.php');
- require_once('../classes/log.php');
- require_once('../classes/session_pool.php');
- <strong>Mock::generate('Log');</strong>
- class TestOfSessionLogging extends UnitTestCase {
-
- function testLoggingInIsLogged() {<strong>
- $log = &new MockLog();
- $log->expectOnce('message', array('User fred logged in.'));</strong>
- $session_pool = &new SessionPool(<strong>$log</strong>);
- $session_pool->logIn('fred');
- }
- }
- ?>
- </pre>
- L'appel <span class="new_code">Mock::generate()</span> a généré
- une nouvelle classe appelé <span class="new_code">MockLog</span>.
- Cela ressemble à un clone identique, sauf que nous pouvons
- y adjoindre du code de test.
- C'est ce que fait <span class="new_code">expectOnce()</span>.
- Cela dit que si <span class="new_code">message()</span> m'est appelé,
- il a intérêt à l'être avec le paramètre
- "User fred logged in.".
- </p>
- <p>
- L'appel <span class="new_code">tally()</span> est nécessaire pour annoncer à
- l'objet fantaisie qu'il n'y aura plus d'appels ultérieurs.
- Sans ça l'objet fantaisie pourrait attendre pendant une
- éternité l'appel de la méthode sans jamais prévenir le
- scénario de test. Les autres tests sont déclenchés
- automatiquement quand l'appel à <span class="new_code">message()</span> est
- invoqué sur l'objet <span class="new_code">MockLog</span> par le code
- <span class="new_code">SessionPool::logIn()</span>.
- L'appel <span class="new_code">mock</span> va déclencher une comparaison des
- paramètres et ensuite envoyer le message "pass" ou "fail"
- au test pour l'affichage. Des jokers peuvent être inclus
- pour ne pas avoir à tester tous les paramètres d'un appel
- alors que vous ne souhaitez qu'en tester un.
- </p>
- <p>
- Les objets fantaisie dans la suite SimpleTest peuvent avoir
- un ensemble de valeurs de sortie arbitraires, des séquences
- de sorties, des valeurs de sortie sélectionnées à partir
- des arguments d'entrée, des séquences de paramètres
- attendus et des limites sur le nombre de fois qu'une
- méthode peut être invoquée.
- </p>
- <p>
- Pour que ce test fonctionne la librairie avec les objets
- fantaisie doit être incluse dans la suite de tests, par
- exemple dans <em>all_tests.php</em>.
- </p>
- <p>
- Pour plus de renseignements sur les objets fantaisie, voyez le
- <a href="mock_objects_documentation.html">documentation sur les objets fantaisie</a>.
- </p>
-
- <h2>
- <a class="target" name="web"></a>Tester une page web</h2>
- <p>
- Une des exigences des sites web, c'est qu'ils produisent
- des pages web. Si vous construisez un projet de A à Z et
- que vous voulez intégrer des tests au fur et à mesure alors
- vous voulez un outil qui puisse effectuer une navigation
- automatique et en examiner le résultat. C'est le boulot
- d'un testeur web.
- </p>
- <p>
- Effectuer un test web via SimpleTest reste assez primitif :
- il n'y a pas de javascript par exemple.
- La plupart des autres opérations d'un navigateur sont simulées.
- </p>
- <p>
- Pour vous donner une idée, voici un exemple assez trivial :
- aller chercher une page web,
- à partir de là naviguer vers la page "about"
- et finalement tester un contenu déterminé par le client.
- <pre>
- <?php
- require_once('simpletest/autorun.php');
- <strong>require_once('simpletest/web_tester.php');</strong>
- class TestOfAbout extends <strong>WebTestCase</strong> {
- function testOurAboutPageGivesFreeReignToOurEgo() {
- <strong>$this->get('http://test-server/index.php');
- $this->click('About');
- $this->assertTitle('About why we are so great');
- $this->assertText('We are really great');</strong>
- }
- }
- ?>
- </pre>
- Avec ce code comme test de recette, vous pouvez vous
- assurer que le contenu corresponde toujours aux
- spécifications à la fois des développeurs et des autres
- parties prenantes au projet.
- </p>
- <p>
- Vous pouvez aussi naviguer à travers des formulaires...
- <pre>
- <?php
- require_once('simpletest/autorun.php');
- require_once('simpletest/web_tester.php');
- class TestOfRankings extends WebTestCase {
- function testWeAreTopOfGoogle() {
- $this->get('http://google.com/');
- $this->setField('q', 'simpletest');
- $this->click("I'm Feeling Lucky");
- $this->assertTitle('SimpleTest - Unit Testing for PHP');
- }
- }
- ?>
- </pre>
- ...même si cela pourrait constituer une violation
- des documents juridiques de Google(tm).
- </p>
- <p>
- Pour plus de renseignements sur comment tester une page web, voyez la
- <a href="web_tester_documentation.html">documentation sur tester des scripts web</a>.
- </p>
- <p>
- <a href="http://sourceforge.net/projects/simpletest/"><img src="http://sourceforge.net/sflogo.php?group_id=76550&type=5" width="210" height="62" border="0" alt="SourceForge.net Logo"></a>
- </p>
-
- </div>
- References and related information...
- <ul>
- <li>
- <a href="https://sourceforge.net/project/showfiles.php?group_id=76550&release_id=153280">Télécharger PHP SimpleTest</a>
- depuis <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
- </li>
- <li>
- L'<a href="http://simpletest.org/api/">API de SimpleTest pour développeur</a>
- donne tous les détails sur les classes et assertions existantes.
- </li>
- </ul>
- <div class="menu_back"><div class="menu">
- <a href="index.html">SimpleTest</a>
- |
- <a href="overview.html">Overview</a>
- |
- <a href="unit_test_documentation.html">Unit tester</a>
- |
- <a href="group_test_documentation.html">Group tests</a>
- |
- <a href="mock_objects_documentation.html">Mock objects</a>
- |
- <a href="partial_mocks_documentation.html">Partial mocks</a>
- |
- <a href="reporter_documentation.html">Reporting</a>
- |
- <a href="expectation_documentation.html">Expectations</a>
- |
- <a href="web_tester_documentation.html">Web tester</a>
- |
- <a href="form_testing_documentation.html">Testing forms</a>
- |
- <a href="authentication_documentation.html">Authentication</a>
- |
- <a href="browser_documentation.html">Scriptable browser</a>
- </div></div>
- <div class="copyright">
- Copyright<br>Marcus Baker 2006
- </div>
- </body>
- </html>
|