テストにおける古典学派とロンドン学派
インプットの記録
ひとりごと
ソフトウェアにおける単体テストは2種類の学派によって分かれている。思考整理をする(前提どちらが良い悪いなく、アーキテクチャと同じようにプロジェクトによって異なる)。
古典学派
実際のオブジェクト等をそのまま利用し、システム全体の振る舞いを検証するテスト手法。つまり、モックやスタブを使わない、もしくは最低限しか用意しない。
メリット
テスト結果が実際の利用シナリオに近い
実践的でシステム全体の統合的な動作確認ができる
テストコード自体が、システムがどう動くかという「ドキュメント」として機能する
デメリット
実際の依存オブジェクトを利用したり、ケースによっては複雑な処理も入ってくるため、一つのテストが大きい
工数的問題
環境依存問題
ロンドン学派
実際のオブジェクトを使わず、モックやスタブ等のテストダブルを用いて、依存関係を隔離し、正しい送受信や、呼び出し順序の検証ができる。古典学派より内部に焦点を当てたり、細かいテストがしやすいテスト手法。
メリット
依存関係はモックで置き換えているので、テストの振る舞いのみを検証できる
テストの実行速度が速い
テストが失敗した時原因を突き止めやすい
デメリット
モックの多用が進むといずれ実際の環境と乖離が生じる可能性がありバグを生む可能性がある
内部実装を変更するたびにテストを修正する必要がある
思うに
プロジェクトによるが結論だが、0→1の開発で早い段階からテストを導入しているなら、古典学派で極力やることがいいのではと思った。テスト自体、ある1機能を1単位(単体)とし、その振る舞いが検証されていればそれで良いと思う。これら2つの最大の違いは、「単体」の定義である。頭出しだけすると、単体はロンドン学派の方が細かい。
例えば、1機能の中に実は5つの実装が隠れていて、それ1つずつを単体としてテストをする、つまり極力細かい粒度のテスト(この例では5つに分解される)になる。これはロンドン学派であるが、そうである必要はない考えている。最終的な目的は1機能の振る舞いが検証されていることだからだ。
私が犬の名前を呼ぶと、その犬は私のところに寄ってきます。
というテスト。と、
私が犬の名前を呼ぶと、その犬は左足を動かし、次に右足を動かし、頭を私の方に向け、しっぽを振り始め・・・
というテスト。やっていることを大袈裟に言うと、前者は古典派で、後者はロンドン派。後者は動作ごとに切り出し、単体テストを実施する。例えば、「その犬は左足を動かし」という1部分を切り取ってそれだけのテストをするとしよう。しかし、それは一体どの方向に進んでいるかわからない。足は前に進んでいても、私のところに寄ってきているかがわからないので我々が本来検証したいことをできていない。語弊がある言い方をすれば、正直そのテストを書いたところで意味がない可能性があるのだ。
あくまで上は一例。逆にロンドン学派のテストの考え方が好きである場合もある。それこそ、リフティはだいぶプロダクトとして出来上がってきてからテストを導入しているので、大きなテストを入れていくよりかは、mockを使ってAPIにバグがないか、公開非公開は正常に振る舞いを満たしているかなどの、「大事な機能を部分的に最小で検証する」にはもってこいの考え方だと思う。
とはいえ長期的な目線や、プロジェクト全体で新しいエンジニアやいろんな開発者が触るプロダクトならば、基本的には古典学派が理想なのではないかなあという感想。テストの単位が小さすぎても、ファイル自体の肥大化や本当に検証すべきことなのかどうかの線引きも難しかったりするので、機能要件を満たすテストを書くなら古典学派の思想があまり迷いなくテストをかけると思った。また、古典学派のようにテストが1機能として書かれていると、テストからプロダクトの動作を理解しやすく、プロダクト開発によりポジティブに直接的な結びつきを得ることができると思った。
インプットして思ったことをながなが綴りましたあああ