修改返回的对象 PHPUnit Mocks 的调用()

2022-08-30 19:40:18

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

假设我有以下类:

class A
{
  function foobar($object) 
  {
    doSomething();
  }
}

这个设置代码:

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

由于某种原因,该对象不会被修改。在我看到它是正确的对象。可能是对象通过值传递吗?如何配置模拟以接收引用?var_dump$object


答案 1

他亚历克斯,

我和 Sebastian(phpunit 的创建者)讨论了这个问题,是的:参数在传递给回调之前被 ed 了。clone

从我的头顶上,我不能给你任何解决方法,但我选择回答无论如何,至少告诉你你没有做错任何事情,这是预期的行为。

引用塞巴斯蒂安斯对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);
    }
}

更新:

从 PHPUnit 3.7 开始,可以关闭克隆。请参阅最后一个参数:

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

默认情况下,它甚至可能处于关闭状态:)


答案 2

执行克隆传递给 mocked 方法的参数的类是 。查看一下,您可以看到,如果参数的类的方法不是公共的,它将返回原始对象。PHPUnit_Framework_MockObject_Invocation_StaticcloneObject()__clone()

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


推荐