Spring BootアプリケーションのテストをSpockで書く方法を説明します。最近のバージョンを対象にしています。
- Spring Boot 1.4
- Spock 1.1-rc-3
- Groovy 2.4
本稿では以下のテストレベルを対象とします。
まずは、build.gradleに依存関係を追加しておきます。
dependencies {
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4-rc-3'
testCompile 'org.spockframework:spock-spring:1.1-groovy-2.4-rc-3'
testRuntime 'cglib:cglib-nodep:3.2.4'
}
コンポーネントテスト
このテストレベルでは、テスト対象の依存コンポーネントをモックに差し替えた状態でテストを行います。
SpockのSpecificationでDIコンテナを利用するには、以下のように@SpringBootTestアノテーションを付加します。
@SpringBootTest(webEnvironment = NONE) class HelloServiceSpec extends Specification { }
これにより@AutowiredでSpringがコンポーネントを注入してくれるようになります。Web Environmentは不要なのでNONEを指定しています。
モックを利用するには@TestConfigurationを定義します。以下のようにDetachedMockFactory#Mock()メソッドでモックオブジェクトを注入することを宣言します。SpockのMock()記法は使えないので注意が必要です。
// Specificationのインナークラス @TestConfiguration static class MockConfig { final detachedMockFactory = new DetachedMockFactory() @Bean ExternalApiClient externalApiClient() { detachedMockFactory.Mock(ExternalApiClient) } }
あとは、Spockのお作法に従ってgivenブロックの中でモックのインタラクションを宣言します。
given: 1 * client.getDefault() >> new Hello('world')
E2Eテスト
このテストレベルでは、テスト対象のAPIに対してHTTPリクエストを投げてレスポンスを検証します。
@SpringBootTestアノテーションにwebEnvironment = RANDOM_PORTを指定することで、実際にアプリケーションサーバが起動した状態でテストを実行できます。
@SpringBootTest(webEnvironment = RANDOM_PORT)
テスト対象にRESTリクエストを送るにはTestRestTemplateクラスを利用します。
@Autowired
TestRestTemplate restTemplate
RestTemplateのお作法に従ってリクエストを送り、レスポンスを検証します。
when: def entity = restTemplate.getForEntity('/hello', Hello) then: entity.statusCode == HttpStatus.OK entity.body.name == 'world'
この場合も`DetachedMockFactory#Mock()で依存コンポーネントをモックに差し替えることが可能です。
まとめ
@SpringBootTestアノテーションでDIコンテナを使ってテストを実行する方法を説明しました。また、DetachedMockFactory#Mock()メソッドで依存コンポーネントをモックに差し替える方法を説明しました。TestRestTemplateクラスを使うとテスト対象APIにRESTリクエストを送信できます。
GitHubにサンプルプロジェクトを置いているので参考にどうぞ。