クラスのメソッドをモックして、パラメーターとして指定されたオブジェクトを変更するコールバックを実行したいと思います(PHP 5.3とPHPUnit3.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
それが正しいオブジェクトだと思います。オブジェクトが値によって渡される可能性がありますか?参照を受け取るようにモックを構成するにはどうすればよいですか?
彼はアレックス、
私はその問題についてSebastian(phpunitの作成者)に話しましたが、そうです。引数はコールバックに渡される前にclone
edになります。
私は頭のてっぺんから回避策を提供することはできませんが、少なくともあなたが何も悪いことをしておらず、これは予想される動作であるとあなたに伝えるためにとにかく答えることを選びます。
セバスチャンのコメントを引用するには、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()
メソッドを追加できます。
これは本当に古いですが、検索の先頭に表示され、正しい方向を示したので、更新する価値があります。 PHPUnit 6.0以降、次のようにdisableArgumentCloning()
を使用します。
return $this->getMockBuilder('A')
->disableOriginalConstructor()
->disableArgumentCloning()
->setMethods(array('foobar'))
->getMock()
;