Изменение объектов в returnCallback () PHPUnit Mocks

Я хочу высмеять метод класса и выполнить обратный вызов, который изменяет объект, указанный как параметр (используя 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 ing $object я вижу, что это правильный объект. Может быть, объект передается по значению? Как настроить макет для получения ссылки?

Он Алекс,

я поговорил с Себастьяном (создателем 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); } } 

Обновить:

Начиная с PHPUnit 3.7, клонирование можно отключить. См. Последний аргумент:

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

Это может даже быть отключено по умолчанию 🙂

Класс, выполняющий клонирование параметров, переданных методу, является PHPUnit_Framework_MockObject_Invocation_Static . Если посмотреть на cloneObject() вы увидите, что он вернет исходный объект, если метод класса __clone() класса параметра не является общедоступным.

Если у вас есть контроль над классом объектов параметров, и вам не нужно их клонировать самостоятельно, вы можете добавить частный пустой метод __clone() .