SimpleTest 模拟问题

发布于 2024-07-23 03:45:51 字数 612 浏览 7 评论 0原文

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

首先,我生成了模拟:

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]”。 我不知道发生了什么 - 这些方法是从该函数调用的!

谢谢,

杰米

I'm writing some test cases, and I've got a test case that is using Mock objects. I need to check to see if two class methods are called from another class method. Here's what I've done:

First I generated the Mock:

Mock::generate('Parser');

Then, inside my test I called:

$P = new MockParser();

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

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

My implementation code looks like:

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

And the loadUrl and parse() methods definately exist. I'm getting two failures on my tests, both telling me "Expected call count for [loadUrl] was [1] got [0]". I've got no idea what's going on - the methods are being called from that function!

Thanks,

Jamie

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

波浪屿的海角声 2024-07-30 03:45:51

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

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

我对 PHP 并没有真正的经验,所以我不想尝试修复你的测试。 希望其他人能做到这一点。

While my experience has been with mocking frameworks in the .NET world, I think that what you're trying to do is incorrect.

Any mocking framework when asked to create a mock for a class, generates "stubs" for ALL the methods in that class. This includes the method fetchAndParse. So when you are calling fetchAndParse on your mock object $P, the methods loadUrl and parse are NOT called. What you are really doing is calling the "stubbed" fetchAndParse method.

I'm not really experienced in PHP, so I don't want to try and fix your test. Hopefully someone else can do that.

节枝 2024-07-30 03:45:51

您误解了嘲笑的工作原理。 如果您使用依赖注入在类中设置辅助对象,那么您可以模拟注入的对象。 之后,您可以模拟原始对象的行为(界面)。 更好的方法是模拟接口,因为您可以在不创建任何实现当前接口的类的情况下进行开发。

以你的例子为例:

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”等单词......一个方法只允许做一件事。 如果你使用这些词,那么你可以确定你的代码设计得很糟糕。

You misunderstood how mocking works. If you use dependency injection to set a helper object in your class, then you can mock your injected object. After that you can simulate the behavior (interface) of the original object. The better way is to mock interfaces, because you can develop without creating any class implementing the current interface.

By your example:

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. your example is a fail, because method names cannot contain words like 'and', 'or', 'if', etc... A method is allowed to do only one thing. If you use these words then you can be sure that you have a bad designed code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文