SimpleTest模拟问题

时间:2009-05-24 13:15:15

标签: php testing simpletest

我正在编写一些测试用例,并且我有一个使用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 个答案:

答案 0 :(得分:4)

虽然我的经验是在.NET世界中使用模拟框架,但我认为你所做的不正确。

当要求为类创建模拟时,任何模拟框架都会为该类中的所有方法生成“存根”。这包括方法fetchAndParse。因此,当您在模拟对象$ P上调用fetchAndParse时,不会调用方法loadUrl和parse。你真正在做的是调用“stubbed”fetchAndParse方法。

我在PHP方面并不是很有经验,所以我不想尝试修复你的测试。希望其他人可以做到这一点。

答案 1 :(得分: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);
    }

}

顺便说一下。你的例子是失败的,因为方法名称不能包含像'和','或','if'等字样......一个方法只允许做一件事。如果您使用这些单词,那么您可以确定您的代码设计错误。