🙆

Testcontainersを使ってJUnitテスト

2021/09/12に公開

https://www.testcontainers.org/

環境

  • Testcontainers 1.16.0
  • JUnit5
  • Gradle
  • Kotlin

準備

build.gradleに以下を追加

dependencies {
    // ...
    testImplementation("org.testcontainers:junit-jupiter:1.16.0")
    testImplementation("org.testcontainers:postgresql:1.16.0")
}

簡単な例

テスト時にコンテナが起動することを確認する。
テストクラスには @Testcontainers を付与する。

@Testcontainers
internal class ExampleTest {
        // テストで使用するコンテナ
    // @Containerを付与すると自動でコンテナの起動と停止をしてくれる。
    @Container
    private val postgreSQLContainer = PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:12.6-alpine"))

    @Test
    fun test() {
        assertTrue(postgreSQLContainer.isRunning)
    }
}

データベース設定の変更

デフォルトだと以下の設定のDBが作られる。

  • データベース名: test
  • ユーザー名: test
  • パスワード: test

withXXXを使って、データベース名などを変えることができる。

@Testcontainers
internal class ExampleTest {
    @Container
    private val postgreSQLContainer = PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:12.6-alpine"))
        .apply {
	    // データベース名とかを変える
            withDatabaseName("foo")
            withUsername("bar")
            withPassword("baz")
	    // 環境変数
	    withEnv("FOO_BAR", "fooBar")
        }

    @Test
    fun test() {
        assertThat(postgreSQLContainer.databaseName).isEqualTo("foo")
        assertThat(postgreSQLContainer.username).isEqualTo("bar")
        assertThat(postgreSQLContainer.password).isEqualTo("baz")
	assertThat(postgreSQLContainer.envMap["FOO_BAR"]).isEqualTo("fooBar")
    }
}

初期化スクリプト

コンテナ起動時にテーブル作成などをすることができる。

resource配下などに適当なSQLファイルを作成する。(今回はresources/create_table.sql)

CREATE TABLE users
(
    id   int          NOT NULL,
    name varchar(100) NOT NULL
);
INSERT INTO users (id, name)
VALUES (1, 'foo'), (2, 'bar'), (3, 'baz');

withInitScriptに作成したSQLファイルを指定する。

@Testcontainers
internal class ExampleTest {
    @Container
    private val postgreSQLContainer = PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:12.6-alpine"))
        .apply {
	    withInitScript("create_table.sql")
        }
}

デバッグでテストを止めるなどして起動中のコンテナに入ると、テーブルが作成されていることがわかる。

$ docker exec -it 20560c6ad322 sh
/ # psql -U test -d test
psql (12.6)
Type "help" for help.

test=# \dt
       List of relations
 Schema | Name  | Type  | Owner
--------+-------+-------+-------
 public | users | table | test
(1 row)

Flyway

初期化スクリプトではなく、Flywayで初期化したりテストデータを投入したりしたい場合。

build.gradleに以下を追加

dependencies {
    // ...
    implementation("org.flywaydb:flyway-core")
}
@Testcontainers
internal class ExampleTest {

    @Container
    private val postgreSQLContainer = PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:12.6-alpine"))
    
    @BeforeEach
    fun setUp() {
        Flyway.configure()
            .dataSource(postgreSQLContainer.jdbcUrl, postgreSQLContainer.username, postgreSQLContainer.password)
            .load()
            .migrate()
    }
}

デバッグなどでテストを止めて起動中のコンテナに入ると、テーブルが作成されていることがわかる。

 docker exec -it 81fa78bfe7d7 sh
/ # psql -U test -d test
psql (12.6)
Type "help" for help.

test=# \dt
               List of relations
 Schema |         Name          | Type  | Owner
--------+-----------------------+-------+-------
 public | flyway_schema_history | table | test
 public | users                 | table | test
(2 rows)

Discussion