業務ではJavaを使用した開発が多いが、単体テストを書いていてMockやStubといったものを使用したことがないことに気がついたため、その使用例をまとめてみる。
Mock, Stubとは
厳密な定義はわからないが、こちらの記事がとても参考に。相互作用に着目するテストで使いたくなるのがMock、状態に着目するテストで欲しくなるのがStubということみたい。
この記事のタイトル “Mocks Aren’t Stubs”にもかかわらず、モックとスタブの違いは本当は一番の問題ではない。最も興味深いのは、相互作用スタイル対状態スタイルというところだ。相互作用中心のテストを行うテスターは全てのサブオブジェクトについてモックを作る。状態中心のテスターは、実際のオブジェクトを使うのが現実的でないものについてのみスタブを作る。例えば、外部サービスやコストのかかるもの、状態中心のやり方では扱いにくいキャッシュのようなものだ。
JUnitでMockitoを使用したテスト
JUnitをMock、Stub作成のためのライブラリであるMockitoと組み合わせて使用してみた。参考にしたのはこちらとこちら。使用例は上の記事に合わせ、倉庫からの商品の引当ロジック(注文に対して在庫が充分に存在するかを判断)のテストとした。
状態中心のテスト(Stub使用)
相互作用中心のテスト(Mock使用)
- 状態に着目したテストはよく見る感じ。
- 相互作用に着目したテストは、例がシンプルすぎたせいか少し良さを感じ辛かった。実際の使用例を見てみたい。例えばVisitorパターンを実装したクラスで、もしvisit順も知りたいとかいう場合は、Mockとしてテストすると簡単そう?
- また、相互作用に着目したテストは内部実装に依存したテストとなる。
Spring FrameworkとMockを使用したテスト
個人的にJavaを使用した開発ではフレームワークとしてSpringを使用することが多いため、SpringにおけるMock利用についても確認した。やりたいのは「Mockオブジェクトを依存性注入」。
Configuration
にconstructorを明示的に設定するという少しトリッキーな方法。だけど調べた感じ一番シンプルにやりたいことができている。
- もちろん他のBeanへのAutowired等も可能。
- この方法が使えるのはinterfaceに対してだけという記述もあったが、試す限りでは通常のクラスに対しても使用できている。
Apache CamelとMockを使用したテスト
あまりメジャーではないかもだけど、データ連携用のJavaフレームワークとしてApache Camelというものがあり、たまに使っている。「置かれたテキストファイルをガーッと読み込み、処理して、別の形式、プロトコルで他に投げる」とかそういうことが簡単に書ける。Apache Camelの概要は日本語の記事だとこちらがわかりやすい。ここではApache CamelでのテストにおけるMock使用法について確認した。やりたいことは「BeanコンポーネントのMock化」
- 最近作られたCDI Testingの仕組みに則って記述。
- BeanコンポーネントのMock化は結局何らかのMock用のクラスを自作するしかなさそう。
- ちなみにRoute自体のMock化ならこちら。もしくはSpring Frameworkと組み合わせてよければ、
@MockEndpointsAndSkip
と@EndpointInject
の合わせ技で書くとすごいラク。
使用したサンプルのリポジトリ