Простая проблема с насмешками - PullRequest
1 голос
/ 24 мая 2009

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

Сначала я сгенерировал макет:

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]». Я понятия не имею, что происходит - методы вызываются из этой функции!

Спасибо

Джейми

Ответы [ 2 ]

4 голосов
/ 24 мая 2009

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

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

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

1 голос
/ 14 марта 2012

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

По вашему примеру:

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

...