【问题标题】:SimpleTest Mocking ProblemSimpleTest 模拟问题
【发布时间】:2009-05-24 13:15:15
【问题描述】:

我正在编写一些测试用例,并且我有一个使用 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]”。我不知道发生了什么 - 正在从该函数调用方法!

谢谢,

杰米

【问题讨论】:

    标签: php testing simpletest


    【解决方案1】:

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

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

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

    【讨论】:

    • 这真的很有帮助 - 这意味着我必须更改相当多的代码,但至少我现在知道发生了什么!谢谢!
    【解决方案2】:

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

    以你为例:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-07
      • 1970-01-01
      • 1970-01-01
      • 2011-04-25
      • 2012-07-19
      • 2011-11-06
      • 2011-08-24
      • 2015-11-13
      相关资源
      最近更新 更多