6

This isn't so much a question as an attempt to save somebody else the hour I just wasted on PHPUnit.

My problem was that my mock object, when used in a dependent test, was not returning the expected value. It seems that PHPUnit does not preserve the same object between dependent tests, even though the syntax makes it look like it does.

Does anyone know why PHPUnit does this? Is this a bug? Things like this in PHPUnit make it very frustrating to use.

<?php 
class PhpUnitTest
extends PHPUnit_Framework_TestCase
{
private $mock;

public function setUp()
{
    $this->mock = $this->getMock('stdClass', array('getFoo'));

    $this->mock->expects( $this->any() )
        ->method('getFoo')
        ->will( $this->returnValue( 'foo' ) );
}

public function testMockReturnValueTwice()
{
    $this->assertEquals('foo', $this->mock->getFoo());
    $this->assertEquals('foo', $this->mock->getFoo());

    return $this->mock;
}

/**
 * @depends testMockReturnValueTwice
 */
public function testMockReturnValueInDependentTest($mock)
{
    /* I would expect this next line to work, but it doesn't! */
    //$this->assertEquals('foo', $mock->getFoo());

    /* Instead, the $mock parameter is not the same object as
     * generated by the previous test! */
    $this->assertNull( $mock->getFoo() );
}

}
4

2 回答 2

5

PHPUnit 中的 Mock 对象附加到为其创建它们的测试实例,根据定义,这意味着单个测试方法。这样做的原因是 PHPUnit 允许您指定在测试期间必须满足的模拟期望。为此,一旦方法成功终止,它就会断言这些期望。如果模拟存在于测试中,那么期望就行不通了。

问题是它不支持存根对象:模拟只包含响应方法和输入的罐头动作。存根不会验证他们的方法是否像完整的模拟那样被调用。也许 PHPUnit 可以从创建setUpBeforeClass()与测试实例无关的存根中受益。

您的另一个选择是使用外部模拟对象库,例如MockeryPhake

编辑:再次查看您的示例代码后,我想知道您为什么对这种行为感到惊讶。正如 Shaunak 所写,setUp()在执行每个测试方法之前在新实例上调用。因此,每个实例都会收到一个新的 mock stdClass。如果您只希望一种测试方法接收期望,请将其添加到测试方法本身中。您仍然可以setUp()使用所有测试方法应该共有的任何行为来创建模拟对象。

于 2011-07-26T07:38:01.007 回答
2

我不是 php 人,如果我错了,请纠正我,但所有单元测试都设计为按以下顺序运行,

设置 --> 测试功能 --> 销毁。

所以每次在执行任何测试函数之前都会调用 setup 和 destroy 函数。这样做是为了保持单元测试的目的。

如果你想拥有依赖的单元测试用例,那么你必须对它们进行编码,而不是依赖全局变量来做到这一点(这违背了单元测试的目的!)。如果有一个依赖于某个函数的测试用例“A”,则从“A”调用该函数,然后断言这些值。

于 2011-07-25T20:50:10.647 回答