MockとかSpyとかStubとかの話と、Jest のMock機能

モックとスタブの違いがわからん!かったが今回ある程度理解したので書き記す。 また Jestの公式ドキュメントのMock機能のページを一通り触りつつ、それぞれがモック・スタブのどちらに当たるか考えていく。

モックとスタブの違い

XUnitPatterns

前提として、モックやスタブの語源、というかネタ元に関して理解する必要がある。 きっと諸説ある類の話なんだろうが、私としては、XUnitPatterns(http://xunitpatterns.com)が元だと考えている。 それを踏まえるとモックとスタブは正確に表現するなら、

  • Mock Object
  • Test Stub

ということになる。まずこの内容を理解するのが良さそうだ。

XUnitPatternsのサイトから理解するのは結構きつい。(英語だし量が多いし。。。) 以下のブログがすごくいい感じにまとめてくれているので参考になる。
xUnit Test PatternsのTest Doubleパターン(Mock、Stub、Fake、Dummy等の定義) - 千里霧中

以降このブログを参考に要点を書き出す。

間接入力と間接出力

理解のためには以下2つの用語がキーになりそうだ。

  • 間接入力
    • 間接入力はテストコードから見えないテスト対象への入力(fetchでhttp GETした場合とか)
  • 間接出力
    • テストコードから見えないテスト対象の出力(fetchでhttp POSTした場合とか)

詳細は上記記事参照のこと

Mock Objectと Test Stub

その上でそれぞれを大体以下の形で理解した。 話の都合でTest Stubから説明する。 どちらもハリボテとして動くモジュールという意味では似ているが、果たす役割は全く逆と言ってもいいかもしれない。

Test Stub

  • Test Stub は SUT(System Under Test = テスト対象)への間接入力を行うためのモジュール。
  • 任意の値をSUTに入力することで、テストの目的に応じてSUTの振る舞いを制御する。
  • どちらかというとSUTの一部として機能するモジュール。

Mock Object

  • Mock Objectは、間接出力を検証するためのモジュール。
  • SUT(System Under Test = テスト対象) からの間接出力の値が妥当かどうかをチェックして、結果をテストコードに返す。
  • Test Stubの機能を包含することもある。
  • どちらかというとテストコードの一部として機能するモジュール。

(おまけ) Test Spy

  • Mockオブジェクトから検証機能を抜いたやつ(雑な説明)
  • 間接出力を受け取りテストコードに投げる。検証はテストコードで行う

注意点

この分類はあくまでXUnitPatterns における分類。世間一般ではモックやスタブは結構色々な意味で使われている可能性がある。 Mock ObjectとTest Stubをまとめてモックと呼ぶ場合もありそう。 そのため人と話す際には認識をきっちり合わせた方が良い。

JestのMock機能の話

上を踏まえた上でJestのMock機能を触ってみた。 Mock Functions · Jest

とりあえず章ごとに軽く所感を残す。 注意点はMock Object(相当) も Test Stub(相当) もどちらもモック機能 で通していること。

「モック関数を利用する」

ここは正しくMockObjectとしての使い方っぽい。forEachのコールバックの部分をMockにして、forEachから コールバックに渡すパラメータを中心に検証している。 うん、間接出力を検証している。まさにMock Objectだな!

「モックの戻り値」

本文に以下のような記載がある通り、これは間接入力を実現するための使い方であり、Test Stub っぽい。

モック関数は、テスト中のコードにテスト用の値を注入するのにも利用できます。

正直こっちの使い方の方が出番が多い気がしてならないので、Test Stubとして使うにもかかわらず mockXXXといった名前の関数を使うことになるので、正直混乱をきたしそうだ。まぁJest的にはモックということなんだろうから受け入れる。

「モジュールのモック」

この機能もかなり出番が多そうだ。また、Mock Object, Test Stubという観点だと、モジュール次第でどちらもあり得る。

例えばドキュメントの例にもある axios であれば、get の場合は値をSUTに渡すだけなので完全に Test Stubだが、postの場合は まず値を渡すのでその検証を行えばMock Objectだが、postのレスポンスをSUTに渡せばTest Stubを包含していることにもなり、まさしく定義通りのMockObjectだ。

最後に

Jestのドキュメントと照らし合わせて、なんとなーくモックとかスタブとかを理解した気持ちになった!☝ ՞ਊ ՞)☝ウェーイ(古)