with() にObjectを渡す検証でNoMatchingExpectationExceptionが出る
mockしたRepositoryクラスのメソッドの呼び出しの検証をするServiceTest.phpを作りました。
public function test_reset_case1_Entityのインスタンスでfail_countが0のデータがrepositoryのresetCountの処理に渡される()
{
$test_id = 1;
$expected = new Entity([
'fail_count'=>0,
]);
$mock_Repository = \Mockery::mock(Repository::class);
$mock_Repository->shouldReceive('resetCount')
->once()
->with($test_id, $expected);
$Service = new Service($mock_Repository);
$Service ->reset($test_id);
}
Service の resetでRepository のメソッドresetCountを呼ぶ検証でMockeryのwith()を使って引数の検証をしています。このテストが下記のようなテスト結果となりました。
1) Tests\Unit\ServiceTest::test_reset_case1_Entityのインスタンスでfail_countが0のデータがrepositoryのresetCountの処理に渡される
Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_0_App_Repository::resetCount(1, object(App\Entity)). Either the method was unexpected or its arguments matched no expected argument list for this method
Objects: ( array (
'App\\Entity' =>
array (
'class' => 'App\\Entity,
'properties' =>
array (
),
),
))
(最初はExceptionのメッセージからmockオブジェクトをLaravelのコンストラクタインジェクションできないのかと思ってしまったのですが、原因は違いました。)
原因: with()の引数にオブジェクトがそのまま渡せない
原因はwith()での検証にobjectをそのまま渡していたことが原因でした。
https://github.com/mockery/mockery/issues/328
代わりにMockery::onで引数の検証を行うクロージャを渡す
https://laradevtips.com/2018/12/01/unit-tests-complex-argument-matching-with-mockeryon-the-right-way/
オブジェクトをwithに渡す場合はMockery::onでtrueを返すclosureを渡し、その中で引数の検証ができるようでした。
public function test_reset_case1_Entityのインスタンスでfail_countが0のデータがrepositoryのresetCountの処理に渡される()
{
$test_id = 1;
$expected = new Entity([
'fail_count'=>0,
]);
$mock_Repository = \Mockery::mock(Repository::class);
$mock_Repository->shouldReceive('resetCount')
->once()
->with($test_id, \Mockery::on(function($actual) use ($expected) {
$this->assertInstanceOf(Entity::class, $actual);
$this->assertEquals($expected, $actual);
return true;
}));
$Service = new Service($mock_Repository);
$Service ->reset($test_id);
}
これでテストが通りました。
... 1 / 1 (100%)
Time: 1.05 seconds, Memory: 16.00 MB
OK (1 tests, 3 assertions)