修改PHPUnit Mocks的returnCallback()中的对象

Ale*_*nce 20 php phpunit

我想模拟一个类的方法并执行一个回调,它修改作为参数给出的对象(使用PHP 5.3和PHPUnit 3.5.5).

假设我有以下课程:

class A
{
  function foobar($object) 
  {
    doSomething();
  }
}
Run Code Online (Sandbox Code Playgroud)

这个设置代码:

$mock = $this->getMockBuilder('A')->getMock();
$mock->expects($this->any())->method('foobar')->will(
  $this->returnCallback(function($object) {
    $object->property = something;
  }));
Run Code Online (Sandbox Code Playgroud)

由于某种原因,对象不会被修改.在var_dump荷兰国际集团$object我认为它是正确的对象.是否可以通过值传递对象?如何配置模拟以接收引用?

edo*_*ian 42

他是Alex,

我和塞巴斯蒂安(phpunit创建者)讨论了这个问题,并且是的:参数在clone传递给回调之前得到了编辑.

从我的头脑中,我不能为你提供任何解决方法,但我选择回答至少告诉你,你没有做错什么,这是预期的行为.

引用Sebastians对IRC的评论为什么它克隆了这个论点:

这是我,我自己和PHPUnit用户之间的长期争论,不管这是否正确;-)

要复制/粘贴一些东西:

此代码示例中的断言3将失败.(该变量仅在返回的对象中更改)

<?php
class A
{
    function foobar($o)
    {
        $o->x = mt_rand(5, 100);
    }
}

class Test extends PHPUnit_Framework_TestCase
{
    public function testFoo()
    {
        $mock = $this->getMock('A');
        $mock->expects($this->any())
             ->method('foobar')
             ->will($this->returnCallback(function($o) { $o->x = 2; return $o; }));

        $o = new StdClass;
        $o->x = 1;

        $this->assertEquals(1, $o->x);
        $return = $mock->foobar($o);

        $this->assertEquals(2, $return->x);
        $this->assertEquals(2, $o->x);
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:

从PHPUnit 3.7开始,可以关闭克隆.查看最后一个参数:

public function getMock(
    $originalClassName, 
    $methods = array(), 
    array $arguments = array(), 
    $mockClassName = '', 
    $callOriginalConstructor = TRUE, 
    $callOriginalClone = TRUE, 
    $callAutoload = TRUE, 
    $cloneArguments = FALSE
);
Run Code Online (Sandbox Code Playgroud)

它甚至可能默认关闭:)

  • 非常感谢您详细和深入研究的回复!即使我现在必须考虑另一种方法来测试我的情况,但很高兴知道这是预期的行为. (2认同)

Dav*_*ess 5

执行克隆传递给模拟方法的参数的类是PHPUnit_Framework_MockObject_Invocation_Static.看看cloneObject()你可以看到,如果参数的类__clone()方法不公开,它将返回原始对象.

如果您可以控制参数对象的类,并且您不需要自己克隆它们,则可以添加私有空__clone()方法.