1

我正在编写一些测试用例,并且我有一个使用 Mock 对象的测试用例。我需要检查是否从另一个类方法调用了两个类方法。这是我所做的:

首先,我生成了 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]”。我不知道发生了什么 - 正在从该函数调用方法!

谢谢,

杰米

4

2 回答 2

4

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

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

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

于 2009-05-24T13:33:37.730 回答
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);
    }

}

顺便提一句。你的例子是失败的,因为方法名称不能包含像'and','or','if'等词......一个方法只允许做一件事。如果您使用这些词,那么您可以确定您的代码设计不佳。

于 2012-03-14T02:22:15.040 回答