mock_objects_documentation.html.svn-base
来自「PHP 知识管理系统(基于树结构的知识管理系统), 英文原版的PHP源码。」· SVN-BASE 代码 · 共 779 行 · 第 1/3 页
SVN-BASE
779 行
en l'occurrence la clef recherch茅e. Maintenant que la m茅thode <span class="new_code">getValue()</span> est invoqu茅e sur l'objet fantaisie...<pre>$config->getValue('db_user')</pre> ...elle renverra "admin". Elle le trouve en essayant de faire correspondre les arguments entrants dans sa liste d'arguments sortants les uns apr猫s les autres jusqu'au moment o霉 une correspondance exacte est atteinte. </p> <p> Il y a des fois o霉 vous souhaitez qu'un objet sp茅cifique soit servi par la fantaisie plut么t qu'une copie. De nouveau c'est identique au m茅canisme des bouchons serveur...<pre>class Thing {}class Vector { function Vector() { } function get($index) { }}</pre> Dans ce cas vous pouvez placer une r茅f茅rence dans la liste renvoy茅e par l'objet fantaisie...<pre>$thing = new Thing();<strong>$vector = &new MockVector($this);$vector->setReturnReference('get', $thing, array(12));</strong></pre> Avec cet arrangement vous savez qu'脿 chaque appel de <span class="new_code">$vector->get(12)</span> le m锚me <span class="new_code">$thing</span> sera renvoy茅. </p> <p><a class="target" name="attentes"><h2>Objets fantaisie en critique</h2></a></p> <p> M锚me si les bouchons serveur vous isolent du d茅sordre du monde r茅el, il ne s'agit l脿 que de la moiti茅 du b茅n茅fice potentiel. Vous pouvez avoir une classe de test recevant les messages ad hoc, mais est-ce que votre nouvelle classe renvoie bien les bons ? Le tester peut devenir cafouillis sans une librairie d'objets fantaisie. </p> <p> Pour l'exemple, prenons une classe <span class="new_code">SessionPool</span> 脿 laquelle nous allons ajouter une fonction de log. Plut么t que de complexifier la classe originale, nous souhaitons ajouter ce comportement avec un d茅corateur (GOF). Pour l'instant le code de <span class="new_code">SessionPool</span> ressemble 脿...<pre><strong>class SessionPool { function SessionPool() { ... } function &findSession($cookie) { ... } ...}class Session { ...}</strong></pre> Alors que pour notre code de log, nous avons...<pre><strong>class Log { function Log() { ... } function message() { ... }}class LoggingSessionPool { function LoggingSessionPool(&$session_pool, &$log) { ... } function &findSession($cookie) { ... } ...}</strong></pre> Dans tout ceci, la seule classe 脿 tester est <span class="new_code">LoggingSessionPool</span>. En particulier, nous voulons v茅rifier que la m茅thode <span class="new_code">findSession()</span> est appel茅e avec le bon identifiant de session au sein du cookie et qu'elle renvoie bien le message "Starting session $cookie" au loggueur. </p> <p> Bien que nous ne testions que quelques lignes de code de production, voici la liste des choses 脿 faire dans un sc茅nario de test conventionnel : <ol> <li>Cr茅er un objet de log.</li> <li>Indiquer le r茅pertoire d'茅criture du fichier de log.</li> <li>Modifier les droits sur le r茅pertoire pour pouvoir y 茅crire le fichier.</li> <li>Cr茅er un objet <span class="new_code">SessionPool</span>.</li> <li>Lancer une session, ce qui demande probablement pas mal de choses.</li> <li>Invoquer <span class="new_code">findSession()</span>.</li> <li>Lire le nouvel identifiant de session (en esp茅rant qu'il existe un accesseur !).</li> <li>Lever une assertion de test pour v茅rifier que cet identifiant correspond bien au cookie.</li> <li>Lire la derni猫re ligne du fichier de log.</li> <li>Supprimer avec une (ou plusieurs) expression rationnelle les timestamps de log en trop, etc.</li> <li>V茅rifier que le message de session est bien dans le texte.</li> </ol> Pas 茅tonnant que les d茅veloppeurs d茅testent 茅crire des tests quand ils sont aussi ingrats. Pour rendre les choses encore pire, 脿 chaque fois que le format de log change ou bien que la m茅thode de cr茅ation des sessions change, nous devons r茅茅crire une partie des tests alors m锚me qu'ils ne testent pas ces parties du syst猫me. Nous sommes en train de pr茅parer le cauchemar pour les d茅veloppeurs de ces autres classes. </p> <p> A la place, voici la m茅thode compl猫te pour le test avec un peu de magie via les objets fantaisie...<pre>Mock::generate('Session');Mock::generate('SessionPool');Mock::generate('Log');class LoggingSessionPoolTest extends UnitTestCase { ... function testFindSessionLogging() {<strong> $session = &new MockSession($this); $pool = &new MockSessionPool($this); $pool->setReturnReference('findSession', $session); $pool->expectOnce('findSession', array('abc')); $log = &new MockLog($this); $log->expectOnce('message', array('Starting session abc')); $logging_pool = &new LoggingSessionPool($pool, $log); $this->assertReference($logging_pool->findSession('abc'), $session); $pool->tally(); $log->tally();</strong> }}</pre> Commen莽ons par 茅crire une session simulacre. Pas la peine d'锚tre trop pointilleux avec celle-ci puisque la v茅rification de la session d茅sir茅e est effectu茅e ailleurs. Nous avons juste besoin de v茅rifier qu'il s'agit de la m锚me que celle qui vient du groupe commun des sessions. </p> <p> <span class="new_code">findSession()</span> est un m茅thode fabrique dont la simulation est d茅crite <a href="#stub">plus haut</a>. Le point de d茅part vient avec le premier appel <span class="new_code">expectOnce()</span>. Cette ligne indique qu'脿 chaque fois que <span class="new_code">findSession()</span> est invoqu茅 sur l'objet fantaisie, il v茅rifiera les arguments entrant. S'il ne re莽oit que la cha卯ne "abc" en tant qu'argument alors un succ猫s est envoy茅 au testeur unitaire, sinon c'est un 茅chec qui est g茅n茅r茅. Il s'agit l脿 de la partie qui teste si nous avons bien la bonne session. La liste des arguments suit une format identique 脿 celui qui pr茅cise les valeurs renvoy茅es. Vous pouvez avoir des jokers et des s茅quences et l'ordre de l'茅valuation restera le m锚me. </p> <p> Si l'appel n'est jamais effectu茅 alors n'est g茅n茅r茅 ni le succ猫s, ni l'茅chec. Pour contourner cette limitation, nous devons dire 脿 l'objet fantaisie que le test est termin茅 : il pourra alors d茅cider si les attentes ont 茅t茅 r茅pondues. L'assertion du testeur unitaire de ceci est d茅clench茅e par l'appel <span class="new_code">tally()</span> 脿 la fin du test. </p> <p> Nous utilisons le m锚me mod猫le pour mettre sur pied le loggueur fantaisie. Nous lui indiquons que <span class="new_code">message()</span> devrait 锚tre invoqu茅 une fois et une fois seulement avec l'argument "Starting session abc". En testant les arguments d'appel, plut么t que ceux de sortie du loggueur, nous isolons le test de tout modification dans le loggueur. </p> <p> Nous commen莽ons le lancement nos tests 脿 la cr茅ation du nouveau <span class="new_code">LoggingSessionPool</span> et nous l'alimentons avec nos objets fantaisie juste cr茅茅s. D茅sormais tout est sous contr么le. Au final nous confirmons que le <span class="new_code">$session</span> donn茅 au d茅corateur est bien celui re莽u et prions les objets fantaisie de lancer leurs tests de comptage d'appel interne avec les appels <span class="new_code">tally()</span>. </p> <p> Il y a encore pas mal de code de test, mais ce code est tr猫s strict. S'il vous semble encore terrifiant il l'est bien moins que si nous avions essay茅 sans les objets fantaisie et ce test en particulier, interactions plut么t que r茅sultat, est toujours plus difficile 脿 mettre en place. Le plus souvent vous aurez besoin de tester des situations plus complexes sans ce niveau ni cette pr茅cision. En outre une partie peut 锚tre remani茅e avec la m茅thode de sc茅nario de test <span class="new_code">setUp()</span>. </p> <p> Voici la liste compl猫te des attentes que vous pouvez placer sur un objet fantaisie avec <a href="http://www.lastcraft.com/simple_test.php">SimpleTest</a>... <table><thead> <tr><th>Attente</th><th>N茅cessite <span class="new_code">tally()</span></th></tr> </thead><tbody><tr> <td><span class="new_code">expectArguments($method, $args)</span></td> <td style="text-align: center">Non</td> </tr> <tr> <td><span class="new_code">expectArgumentsAt($timing, $method, $args)</span></td> <td style="text-align: center">Non</td> </tr> <tr> <td><span class="new_code">expectCallCount($method, $count)</span></td> <td style="text-align: center">Oui</td> </tr> <tr> <td><span class="new_code">expectMaximumCallCount($method, $count)</span></td> <td style="text-align: center">Non</td> </tr> <tr> <td><span class="new_code">expectMinimumCallCount($method, $count)</span></td> <td style="text-align: center">Oui</td> </tr> <tr> <td><span class="new_code">expectNever($method)</span></td> <td style="text-align: center">Non</td> </tr> <tr> <td><span class="new_code">expectOnce($method, $args)</span></td> <td style="text-align: center">Oui</td> </tr> <tr> <td><span class="new_code">expectAtLeastOnce($method, $args)</span></td> <td style="text-align: center">Oui</td>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?