【ミライトデザイン社内勉強会#24】テスト駆動開発、自動テストについて。PHPのinvokeメソッドについて。


Laravelでテスト駆動開発を実際にやってみて、感想や疑問に思ったことをディスカッションした。

## テスト駆動開発について

### フィーチャーテストってプレゼンテーション層のテストって認識でいいの？

- Laravelではコントローラーのテストをフィーチャーテストとして行っている
- Laravelの場合はフレームワークに依存するテストはフィーチャーテスト、依存しないテストはUnitテストにかくことが多い
    - Laravelではこうすることが多いってだけで、フレームワークに依存するからフィーチャーテストってわけじゃない
    - 複数のクラスをつなぎ合わせてテストするのがフィーチャーテスト
        - 部品をつなぎ合わせてテストを行うことが目的
    - 単体のクラスやメソッドをテストするのがUnitテスト
- コントローラーのテストとかモデルのテストとかではなく、機能のテストとか繋ぎ込みのテストとかが観点となる

### 引数を1つずつ追加してテストしながら実装をしていたけど、最初に設計ができていればある程度メソッドを実装した上でテストできそうだけど、どうなの？

- 細かくテストするのは別にいい。細かい単位でテストしていくことで前にテストが通った実装が保証される
- 設計を考えながらやっていくような時に、一個一個テストしながらしたりする






[小さいユニットテストのすすめ](https://zenn.dev/suzuki_hoge/books/2020-12-small-unit-test-65625504e7be1532413f)


### 今はモックのDBとか準備するのが面倒なので基本Unitテストしか書いてないけど、実際テストはどの程度書くものなの？

テストピラミッド

テストは末端の方が低コストなので、費用対効果で考えると良さげ

DB テストサボってブラウザ操作をリリースのたびに超しなきゃいけないなら書く、とか

- バグには出るべきフェーズがある
    - basic auth の設定間違いにブラウザテストで気づくのは妥当
    - 料金計算が間違ってるのにブラウザテストで気づくのは遅い
- 妥当なフェーズで妥当なコストでやろうって考えると良さげ

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364773/af46a567-6ee3-74fe-0ca5-3f7a178d8195.png)


ダミーデータを毎回入れてくれる機能があればやってる

[Laravel8で完成されたModelFactoryの使い方](https://qiita.com/ucan-lab/items/788d1a603f2b53ebb999)

- 全て書くのに越したことはないが、全部が全部書いていくことは難しいので、費用対効果が高いテストを書くのがいい。最悪の最悪ユースケースのフィーチャーテストだけでも書いた方がいい

### フィーチャーテストって基本はUseCaseに書くイメージであってる？？

- Controllerにかくことが多い
- 開発中にフィーチャーテストをすると重たくなることが多いので、開発中はUnitテストをして、プルリク出すときに１回だけ実行することが多い
- DIすればUseCaseの単体テストもできる。
    - ほとんど書くことなくてスカスカになりがちだけど


### みんなは実際にコードを書くときにテスト駆動開発を行っている？
- テストは書いているけど、テスト駆動開発と呼べるものは行っていない
- 最初にコードを全部書いて、その後にテストを書いている
- コードを書いて、テストを書く、を繰り返している。今書いたコードが間違っていないことをテストで保証して、次のコードを描き始めるイメージ。


## PHPのinvokeメソッドの使い所かわからない


https://www.php.net/manual/ja/language.oop5.magic.php#object.invoke

Laravelでinvokeを使う事でシングルアクションコントローラーになる

[PHPの「マジックメソッド」とは――「__set()」「__get()」「__invoke()」の使い方](https://www.atmarkit.co.jp/ait/articles/1804/05/news008_2.html)

- invokeメソッドがある = シングルアクションコントローラーであることが明示される
    - invokeに強制力はないけど（invokeがあっても他のメソッドも追加できてしまう）

    ```php
    class Doubler
    {
        public function __invoke($n)
        {
            return $n * 2;
        }
    }
    ```

    ```php
    $doubler = new Doubler();
    $this->assertEquals(
    	[2, 4, 6],
    	array_map($doubler, [1, 2, 3])
    );
    ```

    `array_map` とかにはまりやすいというメリットはある

    ↓ をシンプルにかける

    ```php
    $this->assertEquals(
    	[2, 4, 6],
    	array_map(function($n) { return $n * 2; }, [1, 2, 3])
    );
    ```

    憶測だけど、無名関数の文法ができる前には価値があったんじゃあないかな

    ↓ 今は再利用したいなら別にこうやって無名関数を束縛すれば、別にいちいちクラスを作らなくても済むし、という意味

    ```php
    $doubler = function($n) { return $n * 2; };
    ```

- Laravelの場合、 __invoke をコントローラで書くとルーティングがシンプルになる

    ```php
    // Laravel側で __invoke メソッドが呼ばれる
    Route::post('/price', PriceController::class)->name('price');

    // Laravel側で price メソッドが呼ばれる
    Route::post('/price', [PriceController::class, 'price'])->name('price');
    ```

    [https://qiita.com/mitsuru793/items/e25b4351e8a63a229b8a#invokeしかできないこと](https://qiita.com/mitsuru793/items/e25b4351e8a63a229b8a#invoke%E3%81%97%E3%81%8B%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8)

- マジックメソッド
    - PHPが準備してくれている関数 + PHPが勝手に呼び出してくれる関数
- magic method は `__toString` が一番イメージしやすいかも

    ```php
    class Foo
    {
        public function __toString()
        {
            return "I'm hoge-san.";
        }
    }
    ```

    ```php
    $foo = new Foo();
    $this->assertEquals("Hello, $foo", "Hello, I'm hoge-san.");
    ```