PHPUnit - 同一个类的多个存根

时间:2010-03-22 22:32:38

标签: php unit-testing collections phpunit stub

我正在为班级Foo建立单元测试,而且我对单元测试还不熟悉。

我的类的一个关键组件是BarCollection的实例,其中包含许多Bar个对象。 Foo中的一个方法遍历集合,并在集合中的每个Bar对象上调用几个方法。我想使用存根对象为我的测试类生成一系列响应。在迭代时,如何使Bar存根类返回不同的值?我正试图沿着这些方向做点什么:

$stubs = array();
foreach ($array as $value) {
    $barStub = $this->getMock('Bar');
    $barStub->expects($this->any())
            ->method('GetValue')
            ->will($this->returnValue($value));
    $stubs[] = $barStub;
}
// populate stubs into `Foo`

// assert results from `Foo->someMethod()`

因此Foo->someMethod()将根据从Bar对象收到的结果生成数据。但是,只要数组长于1,就会出现以下错误:

There was 1 failure:

1) testMyTest(FooTest) with data set #2 (array(0.5, 0.5))
Expectation failed for method name is equal to <string:GetValue> when invoked zero or more times.
Mocked method does not exist.
/usr/share/php/PHPUnit/Framework/MockObject/Mock.php(193) : eval()'d code:25

我有一个想法是使用->will($this->returnCallback())来调用回调方法,但我不知道如何向回调指示哪个Bar对象正在进行调用(以及因此对给)。

另一个想法是使用onConsecutiveCalls()方法或类似的方法来告诉我的存根第一次返回1,第二次返回2等,但我不确定如何做到这一点。我也担心如果我的班级除了对集合进行有序迭代之外还做任何其他事情,我将无法测试它。

3 个答案:

答案 0 :(得分:2)

我很遗憾不确定您是否可以使用 getMock()来解决您的实际问题,但我对 getMock()的体验很渺茫。

只有我能想到的事情,但不知道你的 Bar 类,这可能没有帮助: getMock()的第三个参数允许你传递构造函数参数(作为一个数组)。

我创建了自己的模拟类,将Bar扩展为测试帮助器('只是另一个类恰好在测试中使用的花式名称'),它完全符合我的喜好并将一系列注入到你的 Foo 对象。这为您提供了所需的所有控制权,因为您可以直接替换有问题的方法, getMock()不会这样做。当然这也意味着你没有在这个测试中测试 Bar 类,这可能不是你想要的 - 尽管我建议每个测试类都要编写一个单独的测试类,但是那些不必要的纯粹主义的情况。

$stubs = array();
foreach ($array as $value) {
    $stubs[] = new MyBarTestHelper($value);
}

除此之外,我真的很惊讶你只看到当你有多个数组元素时所描述的异常。我观察到PHPUnit实际上希望你声明任何你希望它能够跟踪为 getMock()参数的方法,并且否则会严重错误,因为它本质上是内部创建的它自己的类扩展,包装你用逻辑明确声明的每个方法,让它确定它是否被调用(=将方法名称添加到逻辑列表中)。

所以让我天真(真的,我可能是,我是一个测试新手,我自己),但看看这对你有什么帮助:

$stubs = array();
foreach ($array as $value) {
    $barStub = $this->getMock('Bar', array('GetValue'));
    $barStub->expects($this->any())
            ->method('GetValue')
            ->will($this->returnValue($value));
    $stubs[] = $barStub;
}

答案 1 :(得分:0)

如果您对使用全局变量感到满意,则应该满足按顺序返回一系列值的要求。它不知道调用了哪个Bar但是如果每个Bar按顺序被Foo调用一次,那么填充测试数据应该不会太难。

$barTestData = array('empty',1,2,3,4,5,6);

function barDataCallback(){
    global $barTestData;
    return next($barTestData);
}

答案 2 :(得分:0)

我注意到在代码中“ - &gt; method('GetValue')”后面有一个额外的括号。不知道你是否复制和粘贴过。