2009-05-24 6 views
1

Je suis en train d'écrire quelques cas de test, et j'ai un cas de test qui utilise des objets Mock. Je dois vérifier si deux méthodes de classe sont appelées d'une autre méthode de classe. Voici ce que je l'ai fait:Problème de simulacre SimpleTest

D'abord, je généré le Mock:

Mock::generate('Parser'); 

Puis, à l'intérieur de mon test, j'ai appelé:

$P = new MockParser(); 

$P->expectOnce('loadUrl', array('http://url')); 
$P->expectOnce('parse'); 

$P->fetchAndParse('http://url'); 

Mon code de mise en œuvre ressemble:

public function fetchAndParse($url) { 
    $this->loadUrl($url); 
    $this->parse(); 
} 

Et les méthodes loadUrl et parse() existent certainement. Je reçois deux échecs lors de mes tests, tous les deux me disant "Le nombre d'appels attendu pour [loadUrl] était de [1] [0]". Je n'ai aucune idée de ce qui se passe - les méthodes sont appelées depuis cette fonction!

Merci,

Jamie

Répondre

4

Bien que mon expérience a été avec moquant des cadres dans le monde .NET, je pense que ce que vous essayez de faire est incorrecte.

Toute structure de simulation lorsqu'on lui a demandé de créer une maquette pour une classe, génère des "stubs" pour TOUTES les méthodes de cette classe. Cela inclut la méthode fetchAndParse. Ainsi, lorsque vous appelez fetchAndParse sur votre objet Mock $ P, les méthodes loadUrl et parse ne sont PAS appelées. Ce que vous faites est d'appeler la méthode "stubbed" fetchAndParse.

Je ne suis pas vraiment expérimenté en PHP, donc je ne veux pas essayer de réparer votre test. J'espère que quelqu'un d'autre peut le faire.

+0

C'est vraiment utile - cela signifie que je dois changer un peu de code, mais au moins je sais maintenant ce qui se passe! Merci! –

1

Vous avez mal compris comment fonctionne la moquerie. Si vous utilisez l'injection de dépendance pour définir un objet d'assistance dans votre classe, vous pouvez simuler votre objet injecté. Après cela, vous pouvez simuler le comportement (interface) de l'objet original. Le mieux est de fausser les interfaces, car vous pouvez développer sans créer de classe implémentant l'interface actuelle.

Par votre exemple:

interface UrlLoaderInterface { 

    public function load($url); 
} 

class YourParser { 

    protected $urlLoader; 
    protected $source; 

    public function setUrlLoader(UrlLoaderInterface $urlLoader) { 
     $this->urlLoader = $urlLoader; 
    } 

    public function fetchAndParse($url) { 
     $this->loadUrl($url); 
     $this->parse(); 
    } 

    public function loadUrl($url) { 
     $this->source = $this->urlLoader->load($url); 
    } 

    public function parse() { 

    } 

} 

Mock::generate('UrlLoaderInterface', 'MockUrlLoader'); 

class TestYourParser extends UnitTestCase { 

    public function testShouldCallUrlLoaderByFetchAndParse() { 
     $testUrl = 'http://url'; 

     $urlLoader = new MockUrlLoader(); 
     $urlLoader->expectOnce('load', array($testUrl)); 
     $urlLoader->returns('load', 'source', array($testUrl)); 

     $parser = new YourParser(); 
     $parser->setUrlLoader($urlLoader); 
     $parser->fetchAndParse($testUrl); 
    } 

} 

btw. votre exemple est un échec, car les noms de méthodes ne peuvent pas contenir des mots comme 'et', 'ou', 'si', etc ... Une méthode est autorisée à faire une seule chose. Si vous utilisez ces mots, vous pouvez être sûr que vous avez un code mal conçu.

Questions connexes