9

我正在为 class 构建单元测试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但是,只要数组长于一个,这就会给我以下错误:

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,等等,但我不确定如何执行此操作。我还担心,如果我的班级除了对集合进行有序迭代之外的任何事情,我将无法测试它。

4

3 回答 3

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;
}
于 2010-03-29T09:31:03.987 回答
0

这应该满足按顺序返回一系列值的要求,如果您习惯使用 global. 它不知道哪个 Bar 被调用,但如果每个 Bar 按顺序被 Foo 调用一次,那么填充测试数据应该不会太难。

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

function barDataCallback(){
    global $barTestData;
    return next($barTestData);
}
于 2010-03-25T19:18:59.893 回答
0

我注意到您的代码中的“->method('GetValue')”之后有一个额外的括号。不知道你有没有复制粘贴。

于 2010-03-26T23:17:37.010 回答