GeekFactory

int128.hatenablog.com

Spring BootアプリのテストをSpockで書く

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にサンプルプロジェクトを置いているので参考にどうぞ。

github.com