LoginSignup
1
1

More than 3 years have passed since last update.

EloquentModelを使ってエンティティを取得しているメソッドのユニットテストの書き方

Posted at

背景

例えばTestModel::findOrFail()とか中でしているメソッドのユニットテストを書くと、どうしてもDBが絡んでユニットテストではなくなってしまう。
これの解決方法。

結論

ExampleService
use App\ExampleModel;

class ExampleService {
    private $exampleModel;

    public function __construct(ExampleModel $exampleModel)
    {
        $this->exampleModel = $exampleModel;
    }

    public function func()
    {
        ...
        $this->exampleModel->findOrfail($id);
        ...
    }
}
ExampleServiceTest
use App\ExampleModel;

...

    $exampleModel = Mockery::mock('\App\ExampleModel')
    $entity = new stdClass;
    $entity->name = $name;
    $exampleModel
        ->shouldReceive('findOrFail')
        ->with($id)
        ->andReturn($entity);
    app()->instance(ExampleModel::class, $exampleModel);
...

解説

EloquentModelはコンストラクタインジェクションで入れておいて、builder機能をインスタンスメソッドで使う

例えばfindOrFail()メソッドなんかはよくstaticメソッドとして実行されるが、内部的には(new static)->$method()とかやってるだけなので、インスタンスメソッドとして実行しても同じものが得られる。
それであればテストの観点からコンストラクタインジェクションで外部からオブジェクトをもらった方が良い。

テストにおいてEloquentModelのクラス名でサービスコンテナに入れておく

Laravelのコンストラクタインジェクションは、そのクラス名でサービスコンテナに探し行く。つまり内部的にはapp()->make(ExampleModel::class)で取ってきていると考えられる。
そうであれば、そのクラス名でmockをサービスコンテナに登録しておけば、テスト時にDBが絡むことを防ぐことが出来る。

1
1
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
1
1