Controller -> Service -> ORMみたいなアプリケーションの場合
ServiceでORMとか依存するクラスをDIでモック出来るように作ると思うんだけど、前しょーもないミスをした
アプリケーション
ORM
<?php class UserOrm { { // DBからUserデータとってくる public function fetchUser(int $user_id): User { DB::selectQuery->where('user_id' , $user_id)->fetch(); } }
Service
<?php class UserService { // DI出来るようにしてる private UserOrm $user_orm; public function __construct(UserOrm $user_orm) { $this->$user_orm = $user_orm; } public function fetchUserAge(int $user_id):int { $user = $user_orm->fetchUser($user_id); return $user->getAge(); } }
Controller
<?php class UserController { // 叩かれたらAgeをレスポンスとして返す public function userAgeApi(int $user_id): Response { // newしたりDIコンテナからとったり $user_orm = new UserOrm(); return (new UserService($user_orm))->fetchUserAge($user_id)->getAge(); } }
よくあるMVC
テストコード
これのテストコード書くときにやらかした
<?php public function testFetchUser() { $age = 20; $user_id = 1; // Userを返すモック $user = new User($user_id); $user->setAge($age); $user_orm = Mockery::mock(UserOrm::class); $user_orm->shouldReceive('fetchUser') ->once() ->with($age) ->andReturn($user); // 期待するAgeが取得できる $actual = (new UserService($user_orm))->fetchUser($user_id); $this->assertSame($age, $actual->getAge()); }
これテストも通るし、パッと見問題ないんだけどControllerからモックを使用せずにテストケース書いた際に死ぬ(事に後々気づく)
原因
ORM
<?php class UserOrm { { // DBからUserデータとってくる public function fetchUser(int $user_id): User { // ここでreturnしてない DB::selectQuery->where('user_id' , $user_id)->fetch(); } }
ORMから何も返してないので当然Ageが取れずに死ぬ
というかそもそも返り値型と一致してなくて死ぬ
思ったこと
- IDE警告してくれるんだからそこで気づくでしょ
- Contorllerのテストケース書けば気づくしまあいいでしょ
みたいなこと考えたんだけど、節穴なのでIDEの警告は見落とすし
Service層で作り固めて最後にControllerの繋ぎこみするプログラミングしてるから検知が遅れてしまって完全にダメダメだった
なんかもう通っちゃいけないのに通すこのテスト、本当に必要か…?みたいな気持ちがあってイマイチ答えが出せずにいる
結局想定するデータ用意するんだし、データDBに突っ込んでモック使わずにControllerからテストしたほうがいいじゃないかと思い始めている
DBに突っ込むとIO増えるからテスト遅くなるんだけど、そこは現代的に並列化とかパワー上げるとかで対処出来るはず
もうテストわからなくて完全にこれになっています