1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
<?xml version="1.0" encoding="ISO-8859-1" ?>
<page title="Sous classer un scnario de test unitaire" here="Sous classer un scnario de test unitaire">
<long_title>Tutorial de test unitaire en PHP - Sous classer un scnario de test</long_title>
<content>
<p>
<a class="target" name="temps"><h2>Une assertion insensible au chronomtre</h2></a>
</p>
<p>
Nous avions laiss notre test d'horloge avec un trou. Si la fonction <code>time()</code> de PHP avanait pendant cette comparaison...
<php><![CDATA[
function testClockTellsTime() {
$clock = new Clock();
$this->assertEqual($clock->now(), time(), 'Now is the right time');
}
]]></php>
...notre test aurait un cart d'une seconde et entranerait un faux chec. Un comportement erratique de notre suite de test n'est vraiment pas ce que nous souhaitons : nous pourrions la lancer une centaine de fois par jour.
</p>
<p>
Nous pourrions r-crire notre test...
<php><![CDATA[
function testClockTellsTime() {
$clock = new Clock();<strong>
$time1 = $clock->now();
$time2 = time();
$this->assertTrue(($time1 == $time2) || ($time1 + 1 == $time2), 'Now is the right time');</strong>
}
]]></php>
Sauf que la conception n'est pas plus claire et que nous devrons le rpter pour chaque test de chronomtrage. Les rptitions sont un ennemi public n1 et donc un trs bon stimulant pour le remaniement de notre code de test.
<php><![CDATA[
class TestOfClock extends UnitTestCase {
function TestOfClock() {
$this->UnitTestCase('Clock class test');
}<strong>
function assertSameTime($time1, $time2, $message) {
$this->assertTrue(
($time1 == $time2) || ($time1 + 1 == $time2),
$message);
}</strong>
function testClockTellsTime() {
$clock = new Clock();<strong>
$this->assertSameTime($clock->now(), time(), 'Now is the right time');</strong>
}
function testClockAdvance() {
$clock = new Clock();
$clock->advance(10);<strong>
$this->assertSameTime($clock->now(), time() + 10, 'Advancement');</strong>
}
}
]]></php>
Bien entendu chaque modification je relance les tests pour bien vrifier que nous sommes dans les clous. Remaniement au vert. C'est beaucoup plus sr.
</p>
<p>
<a class="target" name="sous-classe"><h2>Rutiliser notre assertion</h2></a>
</p>
<p>
Peut-tre voulons nous ajouter d'autres tests sensibles au temps. Peut-tre lisons nous des timestamps - en provenance d'une entre dans une base de donnes ou d'ailleurs - qui tiendraient compte d'une simple seconde pour basculer. Pour que ces nouvelles classes de test profitent de notre nouvelle assertion nous avons besoin de la placer dans une "super classe".
</p>
<p>
Voici notre fichier <em>clock_test.php</em> au complet aprs la promotion de notre mthode <code>assertSameTime()</code> dans sa propre "super classe"...
<php><![CDATA[
<?php
require_once('../classes/clock.php');
<strong>
class TimeTestCase extends UnitTestCase {
function TimeTestCase($test_name) {
$this->UnitTestCase($test_name);
}
function assertSameTime($time1, $time2, $message) {
$this->assertTrue(
($time1 == $time2) || ($time1 + 1 == $time2),
$message);
}
}
class TestOfClock extends TimeTestCase {
function TestOfClock() {
$this->TimeTestCase('Clock class test');
}</strong>
function testClockTellsTime() {
$clock = new Clock();
$this->assertSameTime($clock->now(), time(), 'Now is the right time');
}
function testClockAdvance() {
$clock = new Clock();
$clock->advance(10);
$this->assertSameTime($clock->now(), time() + 10, 'Advancement');
}<strong>
}</strong>
?>
]]></php>
Dsormais nous bnficions de notre nouvelle assertion chaque fois que nous hritons de notre propre classe <code>TimeTestCase</code> plutt que de la classe par dfaut <code>UnitTestCase</code>. Nous retrouvons la conception de l'outil JUnit et SimpleTest est un portage en PHP de cette interface. Il s'agit d'un framework de test partir duquel votre propre systme de test peut s'agrandir.
</p>
<p>
Si nous lanons les tests maintenant une lgre broutille survient...
<div class="demo">
<b>Warning</b>: Missing argument 1 for timetestcase()
in <b>/home/marcus/projects/lastcraft/tutorial_tests/tests/clock_test.php</b> on line <b>5</b><br />
<h1>All tests</h1>
<div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">3/3 test cases complete.
<strong>6</strong> passes and <strong>0</strong> fails.</div>
</div>
La raison est assez dlicate.
</p>
<p>
Notre sous-classe exige un paramtre dans le constructeur qui n'a pas t fourni et pourtant il semblerait que nous l'ayons bel et bien fourni. Quand nous avons hrit de notre nouvelle casse nous lui avons pass notre propre constructeur. C'est juste l...
<php><![CDATA[
function TestOfClock() {
$this->TimeTestCase('Clock class test');
}
]]></php>
En fait nous avons raison, l n'est pas le problme.
</p>
<p>
Vous vous souvenez de quand nous avons construit le test de groupe <em>all_tests.php</em> en utilisant la mthode <code>addTestFile()</code>. Cette mthode recherche les classes de scnario de test, les instancie si elles sont nouvelles puis excute tous nos tests. Ce qui s'est pass ? Elle a aussi trouv notre extension de scnario de test. C'est sans consquence puisque qu'il n'y a pas de mthode de test l'intrieur - comprendre pas de mthode commenant par "test". Aucun test supplmentaire n'est excut.
</p>
<p>
Le problme vient du fait qu'il instancie la classe et le fait sans le paramtre <code>$test_name</code> qui dclenche l'avertissement. Ce paramtre n'est gnralement ncessaire ni pour un scnario de test, ni pour son assertion. Pour que notre scnario de test tendu corresponde l'interface de <code>UnitTestCase</code>, nous avons besoin de le rendre optionnel...
<php><![CDATA[
class TimeTestCase extends UnitTestCase {
function TimeTestCase(<strong>$test_name = false</strong>) {
$this->UnitTestCase($test_name);
}
function assertSameTime($time1, $time2, <strong>$message = false</strong>) {<strong>
if (! $message) {
$message = "Time [$time1] should match time [$time2]";
}</strong>
$this->assertTrue(
($time1 == $time2) || ($time1 + 1 == $time2),
$message);
}
}
]]></php>
Bien sr, que cette classe soit instancie sans raison par la suite de test devrait continuer vous ennuyer. Voici une modification pour l'empcher de s'excuter...
<php><![CDATA[
<strong>SimpleTestOptions::ignore('TimeTestCase');</strong>
class TimeTestCase extends UnitTestCase {
function TimeTestCase($test_name = false) {
$this->UnitTestCase($test_name);
}
function assertSameTime($time1, $time2, $message = '') {
if (!$message) {
$message = "Time [$time1] should match time [$time2]";
}
$this->assertTrue(
($time1 == $time2) || ($time1 + 1 == $time2),
$message);
}
}
]]></php>
Cette ligne ne fait que demander SimpleTest d'ignorer cette classe lors de la construction des suites de test. Elle peut tre ajoute n'importe o dans le fichier de scnario de test.
</p>
<p>
Les six succs ont l'air bien mais ne disent pas un observateur peu attentif ce qui a t test. Pour cela il faut regarder dans le code. Si cela vous parat trop de boulot et que vous prfreriez lire ces informations directement alors vous devriez aller lire comment <a local="display_subclass_tutorial">afficher les succs</a>.
</p>
</content>
<internal>
<link>
Une <a href="#temps">assertion insensible au chronomtre</a> qui permet de gagner une seconde.
</link>
<link>
<a href="#sous-classe">Sous classer un scnario de test</a> afin de rutiliser la mthode de test.
</link>
</internal>
<external>
<link>
Section prcdente : <a local="gain_control_tutorial">contrler les variables de test</a>.
</link>
<link>
Section suivante : <a local="display_subclass_tutorial">changer l'affichage des tests</a>.
</link>
<link>
Vous aurez besoin du <a href="simple_test.php">testeur unitaire SimpleTest</a> pour les exemples.
</link>
</external>
<meta>
<keywords>
dveloppement logiciel,
programmation php,
outils de dveloppement logiciel,
tutorial php,
scripts php gratuits,
organisation de tests unitaires,
cration de sous-classe,
conseil de test,
astuce de dveloppement,
exemple de code php,
objets fantaisie,
junit,
test php,
outil de test unitaire,
suite de test php
</keywords>
</meta>
</page>
|