0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

laravel Mockery オブジェクトの中のオブジェクトの中のプロパティをモック化する

Last updated at Posted at 2024-01-24

概要

オブジェクトの中にある オブジェクトのプロパティをモック化する方法を簡単にまとめておく。

前提

下記のようなメインコードがあったとする。(UserServiceはサービスコンテナに登録されているものとする)
これはmakeHogeObject()の戻り値でHogeオブジェクトが返され、Hogeオブジェクトの中のpiyoオブジェクトの中のnameプロパティにアクセスしている処理だ。

$hogeObject = $this->userService->makeHogeObject();

$name = $hogeObject->piyo->name;

内容

上記のコードが含まれるFeatureテストを書きたい、さらにUserServiceのメソッド実行をモック化したい場合を想定する。(本来Featureテストは、いわゆる「通しのテスト」なのでサービス層のメソッドも含めて動作を確認する場合がほとんどだが、説明の便宜上モック化している。)

まずは下記のように記載してUserServiceをモック化し、サービスコンテナに登録する。

$userServiceMock = Mockery::mock(UserService::class)

$this->app->instance(UserService::class, $userServiceMock);

その後、makeHogeObject()の戻り値をモック化したいので下記のように追記するだろう。ただ書いていく上で、戻り値が若干厄介であることに気がつく。戻り値は「nameプロパティを含む、piyoオブジェクトを含む、Hogeオブジェクト」である必要がある。
オブジェクトが入れ子になっているのでnew Hoge()するだけではだめである。

$userServiceMock = Mockery::mock(UserService::class)

$userServiceMock->shouldReceive('makeHogeObject')->andReturn(/** 戻り値どうしよう、、 */);

$this->app->instance(UserService::class, $userServiceMock);

そこで下記のように書いてみよう。

$userS8erviceMock = Mockery::mock(UserService::class)

$piyoObject = new stdClass(); // stdClassをインスタンス化
$piyoObject->name = 'ぴよぴよ'; // nameプロパティを設定
$hogeObject = new Hoge(); // Hogeオブジェクト作成
$hogeObject->piyo = $piyoObject; // HogeオブジェクトにstdClassから作ったPiyoオブジェクトを格納
$userServiceMock->shouldReceive('makeHogeObject')->andReturn($hogeObject); // お膳立てされたHogeオブジェクトを返却

$this->app->instance(UserService::class, $userServiceMock);

※stdClassについてはこちら↓

複雑に見えるが、これでお膳立てはできたっぽい。

余談

実は$hogeObject = new Hoge(); // Hogeオブジェクト作成の部分は本物のHogeクラスをインスタンス化しなくても良い。下記のような書き方もできる。

$userS8erviceMock = Mockery::mock(UserService::class)

$piyoObject = new stdClass(); // stdClassをインスタンス化
$piyoObject->name = 'ぴよぴよ'; // nameプロパティを設定
$hogeObject = Mockery::mock(Hoge::class); // Hogeオブジェクト作成
$hogeObject->piyo = $piyoObject; // HogeオブジェクトにstdClassから作ったPiyoオブジェクトを格納
$userServiceMock->shouldReceive('makeHogeObject')->andReturn($hogeObject); // お膳立てされたHogeオブジェクトを返却

$this->app->instance(UserService::class, $userServiceMock);

しかし、Hogeクラスがライブラリにて用意されたクラスだと、does not exist on this mock objectなどのエラーが出る時がある。

これはHogeクラスに静的メソッドや静的プロパティが定義されていて、それが処理の一貫で外部からのアクセスを受けたりすると出るエラーである。(モックとして側だけHogeオブジェクトを作成しているので静的メソッドなどが定義されていない。ようは呼び出そうとしたメソッドやプロパティが無いことで怒られている。)

その場合は今回紹介した方法で地道にお膳立てをするか、下記のようにすることで解決することもある。(overloadを使う方法)下記の方法は若干無理矢理感がある気がして自分は今回紹介した方法が好みだ。

$userS8erviceMock = Mockery::mock(UserService::class)

$piyoObject = new stdClass(); // stdClassをインスタンス化
$piyoObject->name = 'ぴよぴよ'; // nameプロパティを設定
$hogeObject = Mockery::mock('overload:' . Hoge::class); // Hogeオブジェクト作成
$hogeObject->piyo = $piyoObject; // HogeオブジェクトにstdClassから作ったPiyoオブジェクトを格納
$userServiceMock->shouldReceive('makeHogeObject')->andReturn($hogeObject); // お膳立てされたHogeオブジェクトを返却

$this->app->instance(UserService::class, $userServiceMock);
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?