2009-05-24 3 views
1

Я пишу несколько тестовых примеров, и у меня есть тестовый пример, в котором используются объекты Mock. Мне нужно проверить, вызваны ли два метода класса из другого метода класса. Вот что я сделал:Простая задача Mocking

Сначала я создал Мок:

Mock::generate('Parser'); 

Тогда, в моем тесте я назвал:

$P = new MockParser(); 

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

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

Мой код реализации выглядит следующим образом:

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

И методы loadUrl и parse() определенно существуют. Я получаю две неудачи в своих тестах, оба говорят мне: «Ожидаемый счетчик вызовов для [loadUrl] был [1] получил [0]». Я понятия не имею, что происходит - методы вызываются из этой функции!

Спасибо,

Джейми

ответ

4

Хотя мой опыт был с насмешливым рамки в мире .NET, я думаю, что вы пытаетесь сделать, это неправильно.

Любое издевательское фреймворк, когда его просят создать макет для класса, генерирует «заглушки» для ВСЕХ методов в этом классе. Сюда входит метод fetchAndParse. Поэтому, когда вы вызываете fetchAndParse на ваш макет объекта $ P, методы loadUrl и parse НЕ вызывают. То, что вы на самом деле делаете, - это вызов «обрезанного» метода fetchAndParse.

У меня на самом деле нет опыта работы на PHP, поэтому я не хочу пытаться исправить ваш тест. Надеюсь, кто-то может это сделать.

+0

Это действительно полезно - это значит, что мне нужно изменить совсем немного кода, но по крайней мере теперь я знаю, что происходит! Благодаря! –

1

Вы неправильно поняли, как насмешливые работы. Если вы используете инъекцию зависимостей для установки вспомогательного объекта в своем классе, вы можете издеваться над вашим инъецированным объектом. После этого вы можете моделировать поведение (интерфейс) исходного объекта. Лучший способ - обмануть интерфейсы, потому что вы можете развиваться без создания какого-либо класса, реализующего текущий интерфейс.

На вашем примере:

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. ваш пример является сбоем, потому что имена методов не могут содержать такие слова, как «и», «или», «если» и т. д. Метод допускает выполнение только одной вещи. Если вы используете эти слова, вы можете быть уверены, что у вас плохо разработанный код.