简体   繁体   English

SimpleTest模拟问题

[英]SimpleTest Mocking Problem

I'm writing some test cases, and I've got a test case that is using Mock objects. 我正在编写一些测试用例,并且有一个使用Mock对象的测试用例。 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:

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. 并确实存在loadUrl和parse()方法。 I'm getting two failures on my tests, both telling me "Expected call count for [loadUrl] was [1] got [0]". 我在测试中遇到了两次失败,都告诉我“ [loadUrl]的预期调用计数为[1]得到[0]”。 I've got no idea what's going on - the methods are being called from that function! 我不知道发生了什么-该函数正在调用该方法!

Thanks, 谢谢,

Jamie 杰米

While my experience has been with mocking frameworks in the .NET world, I think that what you're trying to do is incorrect. 虽然我曾在.NET世界中使用过模拟框架,但我认为您尝试做的是不正确的。

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. 这包括方法fetchAndParse。 So when you are calling fetchAndParse on your mock object $P, the methods loadUrl and parse are NOT called. 因此,当您在模拟对象$ P上调用fetchAndParse时,不会调用loadUrl和parse方法。 What you are really doing is calling the "stubbed" fetchAndParse method. 您真正在做的是调用“存根” fetchAndParse方法。

I'm not really experienced in PHP, so I don't want to try and fix your test. 我对PHP没有真正的经验,所以我不想尝试修复您的测试。 Hopefully someone else can do that. 希望其他人可以做到这一点。

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. 您的示例失败了,因为方法名称不能包含'and','or','if'等单词。...方法只能做一件事。 If you use these words then you can be sure that you have a bad designed code. 如果使用这些词,则可以确保设计的代码错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM