Spring Framework軽量テストへの道
#WIP
SpringのDIコンテナの起動が数秒かかると、1ケースの実行では問題なくても積み重なると大きな時間を占めることになる。
StaticApplicationContext
Springのコンテナにはいくつか種類があって、StaticApplicationContextはコンポーネントの登録に、明示的にregisterする手段しかもたないものである。Guiceのような使い方ができる。
code:Test.java
import org.springframework.context.support.StaticApplicationContext;
import static org.mockito.Mockito.*;
class HogeControllerTest {
StaticApplicationContext context;
@BeforeEach
void setup() {
context = new StaticApplicationContext();
context.registerBean(HogeController.class);
context.registerBean(HogeUsecase.class, this::mockHogeUsecase);
}
@Test
void test() {
HogeController controller = context.getBean(HogeController.class);
controller.processHoge();
verify(context.getBean(HogeUsecase.class), times(1)).verifyHoge(any());
}
private HogeUsecase mockHogeUsecase() {
HogeUsecase mock = mock(HogeUsecase.class);
// … MockObjectのふるまい定義
return mock;
}
}
コンポーネントのインタフェースを作る
コンポーネントの依存が多く、テストするにも多くの依存コンポーネントも必要とする場合は、そのコンポーネント自体をモック化することになるだろう。
何の戦略なしにコンポーネントをモック化してテストを書くと、何をテストしているかわからない状態に陥る。レイヤードアーキテクチャでは、下のレイヤーのコンポーネントだけをモック化するのが基本だ。
そうは言っても、同じレイヤーの中で多くのコンポーネントに依存しまくっているアプリケーションに対して、テストを書いていかなくてはならないこともある。そうしたケースでは、IDEのリファクタリング機能を使って、モック化したいコンポーネントのインタフェースを抽出すると良い。具象クラスをモック化しようとすると、結局実装の詳細を見に行かなきゃいけなくなる、その負荷をへらすためである。さらには、そのインタフェースに対して、テストでも使えるようにデフォルト実装を用意しておくとなお良い。(フレームワーク本体ではよく見られるテクニックである)
https://github.com/spring-projects/spring-framework/search?q=Default
https://github.com/netty/netty/search?q=Default