1
0
mirror of synced 2024-12-15 23:56:02 +03:00
doctrine2/vendor/simpletest/docs/fr/expectation_documentation.html

264 lines
14 KiB
HTML
Raw Normal View History

2007-01-29 01:39:21 +03:00
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Documentation SimpleTest : &eacute;tendre le testeur unitaire avec des classes d'attentes suppl&eacute;mentaires</title>
<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
</head>
<body>
<div class="menu_back">
<div class="menu">
<h2>
<a href="index.html">SimpleTest</a>
</h2>
<ul>
<li>
<a href="overview.html">Overview</a>
</li>
<li>
<a href="unit_test_documentation.html">Unit tester</a>
</li>
<li>
<a href="group_test_documentation.html">Group tests</a>
</li>
<li>
<a href="server_stubs_documentation.html">Server stubs</a>
</li>
<li>
<a href="mock_objects_documentation.html">Mock objects</a>
</li>
<li>
<a href="partial_mocks_documentation.html">Partial mocks</a>
</li>
<li>
<a href="reporter_documentation.html">Reporting</a>
</li>
<li>
<a href="expectation_documentation.html">Expectations</a>
</li>
<li>
<a href="web_tester_documentation.html">Web tester</a>
</li>
<li>
<a href="form_testing_documentation.html">Testing forms</a>
</li>
<li>
<a href="authentication_documentation.html">Authentication</a>
</li>
<li>
<a href="browser_documentation.html">Scriptable browser</a>
</li>
</ul>
</div>
</div>
<h1>Documentation sur les attentes</h1>
<div class="content">
<p>
<a class="target" name="fantaisie">
<h2>Plus de contr&ocirc;le sur les objets fantaisie</h2>
</a>
</p>
<p>
Le comportement par d&eacute;faut des <a href="mock_objects_documentation.html">objets fantaisie</a> dans <a href="http://sourceforge.net/projects/simpletest/">SimpleTest</a> est soit une correspondance identique sur l'argument, soit l'acceptation de n'importe quel argument. Pour la plupart des tests, c'est suffisant. Cependant il est parfois n&eacute;cessaire de ramollir un sc&eacute;nario de test.
</p>
<p>
Un des endroits o&ugrave; un test peut &ecirc;tre trop serr&eacute; est la reconnaissance textuelle. Prenons l'exemple d'un composant qui produirait un message d'erreur utile lorsque quelque chose plante. Il serait utile de tester que l'erreur correcte est renvoy&eacute;e, mais le texte proprement dit risque d'&ecirc;tre plut&ocirc;t long. Si vous testez le texte dans son ensemble alors &agrave; chaque modification de ce m&ecirc;me message -- m&ecirc;me un point ou une virgule -- vous aurez &agrave; revenir sur la suite de test pour la modifier.
</p>
<p>
Voici un cas concret, nous avons un service d'actualit&eacute;s qui a &eacute;chou&eacute; dans sa tentative de connexion &agrave; sa source distante.
<pre>
<strong>class NewsService {
...
function publish(&amp;$writer) {
if (! $this-&gt;isConnected()) {
$writer-&gt;write('Cannot connect to news service "' .
$this-&gt;_name . '" at this time. ' .
'Please try again later.');
}
...
}
}</strong>
</pre>
L&agrave; il envoie son contenu vers un classe <span class="new_code">Writer</span>. Nous pourrions tester ce comportement avec un <span class="new_code">MockWriter</span>...
<pre>
class TestOfNewsService extends UnitTestCase {
...
function testConnectionFailure() {<strong>
$writer = &amp;new MockWriter($this);
$writer-&gt;expectOnce('write', array(
'Cannot connect to news service ' .
'"BBC News" at this time. ' .
'Please try again later.'));
$service = &amp;new NewsService('BBC News');
$service-&gt;publish($writer);
$writer-&gt;tally();</strong>
}
}
</pre>
C'est un bon exemple d'un test fragile. Si nous d&eacute;cidons d'ajouter des instructions compl&eacute;mentaires, par exemple proposer une source d'actualit&eacute;s alternative, nous casserons nos tests par la m&ecirc;me occasion sans pourtant avoir modifi&eacute; une seule fonctionnalit&eacute;.
</p>
<p>
Pour contourner ce probl&egrave;me, nous voudrions utiliser un test avec une expression rationnelle plut&ocirc;t qu'une correspondance exacte. Nous pouvons y parvenir avec...
<pre>
class TestOfNewsService extends UnitTestCase {
...
function testConnectionFailure() {
$writer = &amp;new MockWriter($this);<strong>
$writer-&gt;expectOnce(
'write',
array(new WantedPatternExpectation('/cannot connect/i')));</strong>
$service = &amp;new NewsService('BBC News');
$service-&gt;publish($writer);
$writer-&gt;tally();
}
}
</pre>
Plut&ocirc;t que de transmettre le param&egrave;tre attendu au <span class="new_code">MockWriter</span>, nous envoyons une classe d'attente appel&eacute;e <span class="new_code">WantedPatternExpectation</span>. L'objet fantaisie est suffisamment &eacute;l&eacute;gant pour reconna&icirc;tre qu'il s'agit d'un truc sp&eacute;cial et pour le traiter diff&eacute;remment. Plut&ocirc;t que de comparer l'argument entrant &agrave; cet objet, il utilise l'objet attente lui-m&ecirc;me pour ex&eacute;cuter le test.
</p>
<p>
<span class="new_code">WantedPatternExpectation</span> utilise l'expression rationnelle pour la comparaison avec son constructeur. A chaque fois q'une comparaison est fait &agrave; travers <span class="new_code">MockWriter</span> par rapport &agrave; cette classe attente, elle fera un <span class="new_code">preg_match()</span> avec ce motif. Dans notre sc&eacute;nario de test ci-dessus, aussi longtemps que la cha&icirc;ne "cannot connect" appara&icirc;t dans le texte, la fantaisie transmettra un succ&egrave;s au testeur unitaire. Peu importe le reste du texte.
</p>
<p>
Les classes attente possibles sont...
<table>
<tbody>
<tr>
<td><span class="new_code">EqualExpectation</span></td><td>Une &eacute;galit&eacute;, plut&ocirc;t que la plus forte comparaison &agrave; l'identique</td>
</tr>
<tr>
<td><span class="new_code">NotEqualExpectation</span></td><td>Une comparaison sur la non-&eacute;galit&eacute;</td>
</tr>
<tr>
<td><span class="new_code">IndenticalExpectation</span></td><td>La v&eacute;rification par d&eacute;faut de l'objet fantaisie qui doit correspondre exactement</td>
</tr>
<tr>
<td><span class="new_code">NotIndenticalExpectation</span></td><td>Inverse la logique de l'objet fantaisie</td>
</tr>
<tr>
<td><span class="new_code">WantedPatternExpectation</span></td><td>Utilise une expression rationnelle Perl pour comparer une cha&icirc;ne</td>
</tr>
<tr>
<td><span class="new_code">NoUnwantedPatternExpectation</span></td><td>Passe seulement si l'expression rationnelle Perl &eacute;choue</td>
</tr>
<tr>
<td><span class="new_code">IsAExpectation</span></td><td>V&eacute;rifie le type ou le nom de la classe uniquement</td>
</tr>
<tr>
<td><span class="new_code">NotAExpectation</span></td><td>L'oppos&eacute; de <span class="new_code">IsAExpectation</span></td>
</tr>
<tr>
<td><span class="new_code">MethodExistsExpectation</span></td><td>V&eacute;rifie si la m&eacute;thode est disponible sur un objet</td>
</tr>
</tbody>
</table>
La plupart utilisent la valeur attendue dans le constructeur. Les exceptions sont les v&eacute;rifications sur motif, qui utilisent une expression rationnelle, ainsi que <span class="new_code">IsAExpectation</span> et <span class="new_code">NotAExpectation</span>, qui prennent un type ou un nom de classe comme cha&icirc;ne.
</p>
<p>
<a class="target" name="comportement">
<h2>Utiliser les attentes pour contr&ocirc;ler les bouchons serveur</h2>
</a>
</p>
<p>
Les classes attente peuvent servir &agrave; autre chose que l'envoi d'assertions depuis les objets fantaisie, afin de choisir le comportement d'un <a href="mock_objects_documentation.html">objet fantaisie</a> our celui d'un <a href="server_stubs_documentation.html">bouchon serveur</a>. A chaque fois qu'une liste d'arguments est donn&eacute;e, une liste d'objets attente peut &ecirc;tre ins&eacute;r&eacute;e &agrave; la place.
</p>
<p>
Mettons que nous voulons qu'un bouchon serveur d'autorisation simule une connexion r&eacute;ussie seulement si il re&ccedil;oit un objet de session valide. Nous pouvons y arriver avec ce qui suit...
<pre>
Stub::generate('Authorisation');
<strong>
$authorisation = new StubAuthorisation();
$authorisation-&gt;setReturnValue(
'isAllowed',
true,
array(new IsAExpectation('Session', 'Must be a session')));
$authorisation-&gt;setReturnValue('isAllowed', false);</strong>
</pre>
Le comportement par d&eacute;faut du bouchon serveur est d&eacute;fini pour renvoyer <span class="new_code">false</span> quand <span class="new_code">isAllowed</span> est appel&eacute;. Lorsque nous appelons cette m&eacute;thode avec un unique param&egrave;tre qui est un objet <span class="new_code">Session</span>, il renverra <span class="new_code">true</span>. Nous avons aussi ajout&eacute; un deuxi&egrave;me param&egrave;tre comme message. Il sera affich&eacute; dans le message d'erreur de l'objet fantaisie si l'attente est la cause de l'&eacute;chec.
</p>
<p>
Ce niveau de sophistication est rarement utile : il n'est inclut que pour &ecirc;tre complet.
</p>
<p>
<a class="target" name="etendre">
<h2>Cr&eacute;er vos propres attentes</h2>
</a>
</p>
<p>
Les classes d'attentes ont une structure tr&egrave;s simple. Tellement simple qu'il devient tr&egrave;s simple de cr&eacute;er vos propres version de logique pour des tests utilis&eacute;s couramment.
</p>
<p>
Par exemple voici la cr&eacute;ation d'une classe pour tester la validit&eacute; d'adresses IP. Pour fonctionner correctement avec les bouchons serveurs et les objets fantaisie, cette nouvelle classe d'attente devrait &eacute;tendre <span class="new_code">SimpleExpectation</span>...
<pre>
<strong>class ValidIp extends SimpleExpectation {
function test($ip) {
return (ip2long($ip) != -1);
}
function testMessage($ip) {
return "Address [$ip] should be a valid IP address";
}
}</strong>
</pre>
Il n'y a v&eacute;ritablement que deux m&eacute;thodes &agrave; mettre en place. La m&eacute;thode <span class="new_code">test()</span> devrait renvoyer un <span class="new_code">true</span> si l'attente doit passer, et une erreur <span class="new_code">false</span> dans le cas contraire. La m&eacute;thode <span class="new_code">testMessage()</span> ne devrait renvoyer que du texte utile &agrave; la compr&eacute;hension du test en lui-m&ecirc;me.
</p>
<p>
Cette classe peut d&eacute;sormais &ecirc;tre employ&eacute;e &agrave; la place des classes d'attente pr&eacute;c&eacute;dentes.
</p>
<p>
<a class="target" name="unitaire">
<h2>Sous le capot du testeur unitaire</h2>
</a>
</p>
<p>
Le <a href="http://sourceforge.net/projects/simpletest/">frameworkd de test unitaire SimpleTest</a> utilise aussi dans son coeur des classes d'attente pour la <a href="unit_test_documentation.html">classe UnitTestCase</a>. Nous pouvons aussi tirer parti de ces m&eacute;canismes pour r&eacute;utiliser nos propres classes attente &agrave; l'int&eacute;rieur m&ecirc;me des suites de test.
</p>
<p>
La m&eacute;thode la plus directe est d'utiliser la m&eacute;thode <span class="new_code">SimpleTest::assertExpectation()</span> pour effectuer le test...
<pre>
<strong>class TestOfNetworking extends UnitTestCase {
...
function testGetValidIp() {
$server = &amp;new Server();
$this-&gt;assertExpectation(
new ValidIp(),
$server-&gt;getIp(),
'Server IP address-&gt;%s');
}
}</strong>
</pre>
C'est plut&ocirc;t sale par rapport &agrave; notre syntaxe habituelle du type <span class="new_code">assert...()</span>.
</p>
<p>
Pour un cas aussi simple, nous cr&eacute;ons d'ordinaire une m&eacute;thode d'assertion distincte en utilisant la classe d'attente. Supposons un instant que notre attente soit un peu plus compliqu&eacute;e et que par cons&eacute;quent nous souhaitions la r&eacute;utiliser, nous obtenons...
<pre>
class TestOfNetworking extends UnitTestCase {
...<strong>
function assertValidIp($ip, $message = '%s') {
$this-&gt;assertExpectation(new ValidIp(), $ip, $message);
}</strong>
function testGetValidIp() {
$server = &amp;new Server();<strong>
$this-&gt;assertValidIp(
$server-&gt;getIp(),
'Server IP address-&gt;%s');</strong>
}
}
</pre>
Il est peu probable que nous ayons besoin de ce niveau de contr&ocirc;le sur la machinerie de test. Il est assez rare que le besoin d'une attente d&eacute;passe le stade de la reconnaissance d'un motif. De plus, les classes d'attente complexes peuvent rendre les tests difficiles &agrave; lire et &agrave; d&eacute;boguer. Ces m&eacute;canismes sont v&eacute;ritablement l&agrave; pour les auteurs de syst&egrave;me qui &eacute;tendront le framework de test pour leurs propres outils de test.
</p>
</div>
<div class="copyright">
Copyright<br>Marcus Baker, Jason Sweat, Perrick Penet 2004
</div>
</body>
</html>