KotestでTestcontainersを簡単に使う方法になります。
KotestのTestcontainers拡張を追加
KotestにはTestcontainers用の拡張ライブラリが用意されているので、それを依存に追加します。
build.gradleの場合
testImplementation 'io.kotest.extensions:kotest-extensions-testcontainers:1.1.1'
pom.xmlの場合
<dependency> <groupId>io.kotest.extensions</groupId> <artifactId>kotest-extensions-testcontainers</artifactId> <version>1.1.1</version> <scope>test</scope> </dependency>
デフォルト構成Testcontainerを使ってみる
テストコード
WireMock
のコンテナをTestcontainersで起動するテストコードになります。
TestContainerExtension
にimageを指定して、install
することでコンテナを上げることができます。
class TestContainerExample : FreeSpec({ val container = install(TestContainerExtension("wiremock/wiremock:latest")) { withExposedPorts(8080) } (1..5).forEach { "test $it" { println("test $it") println("container.containerId = ${container.containerId}") println("container.getMappedPort(8080) = ${container.getMappedPort(8080)}") } } })
実行結果
実行結果を見ると、コンテナが起動され公開されたポートがホスト側のポートにマッピングされていることが確認できます。 デフォルトでは、全てのテストケースで同じコンテナを使いまわしするようです。(Spec単位でコンテナが管理されます)
test 1 container.containerId = 74716ee4e1bf41bb73012c95648698f2a22b06e1ff670dbc187096735fa39bb2 container.getMappedPort(8080) = 49190 test 2 container.containerId = 74716ee4e1bf41bb73012c95648698f2a22b06e1ff670dbc187096735fa39bb2 container.getMappedPort(8080) = 49190 test 3 container.containerId = 74716ee4e1bf41bb73012c95648698f2a22b06e1ff670dbc187096735fa39bb2 container.getMappedPort(8080) = 49190 test 4 container.containerId = 74716ee4e1bf41bb73012c95648698f2a22b06e1ff670dbc187096735fa39bb2 container.getMappedPort(8080) = 49190 test 5 container.containerId = 74716ee4e1bf41bb73012c95648698f2a22b06e1ff670dbc187096735fa39bb2 container.getMappedPort(8080) = 49190
テストケース単位でコンテナを使い捨てる構成にしてみる
テストコード
TestContainerExtension
にLifecycleMode.EveryTest
を指定することで、テストケース単位にコンテナが起動されクリーンな状態でテストが実行できるようになります。
class TestContainerExample : FreeSpec({ val container = install(TestContainerExtension("wiremock/wiremock:latest", LifecycleMode.EveryTest)) { withExposedPorts(8080) } (1..5).forEach { "test $it" { println("test $it") println("container.containerId = ${container.containerId}") println("container.getMappedPort(8080) = ${container.getMappedPort(8080)}") } } })
実行結果
実行結果を見るとテストごとにコンテナIDが変わっていることが確認できるので、LifecycleMode
の指定が効いていることが確認できます。
test 1 container.containerId = 74bd2ffd8304eebbdb57281b5e7bd818f379036caf314fe36714ba877edd80f3 container.getMappedPort(8080) = 49192 test 2 container.containerId = a278dd9a16a066e1dd0beb5785c4b61ec3088c96c89d9bbc8deedb0f2cd7d99c container.getMappedPort(8080) = 49193 test 3 container.containerId = 6b47542b908d6da7b2a5a9aad7997840b0c626fd08851c1f0140691629e9f861 container.getMappedPort(8080) = 49194 test 4 container.containerId = 54dedc990cde75c608c0491f1d12d4cc7ee779a0e24587665341929f3a5b3108 container.getMappedPort(8080) = 49195 test 5 container.containerId = f4237335e4d9bb167dc07b1b466f23b2e22101c1d0dbc3470e8092688c034e7d container.getMappedPort(8080) = 49196
データベースを扱ってみる
データベースを扱う際には、Testcontainersの使用したいデータベースのモジュールを使用してコンテナを上げるのが簡単です。
テストコードで、データベースにアクセスしたい場合には、 JdbcTestContainerExtension
を使用することで立ち上げたコンテナに対する接続を持ったHikariDataSource
を取得することができます。
HikariDataSource
があれば、データのセットアップ系などの処理も簡単に行えるので良さそうですね。
build.gradle
testImplementation "org.testcontainers:postgresql:1.16.3" testRuntimeOnly 'org.postgresql:postgresql:42.3.1'
テストコード
class TestContainerExample : FreeSpec({ val postgresql = PostgreSQLContainer<Nothing>("postgres:9.6.24-stretch") val datasource = install(JdbcTestContainerExtension(postgresql)) { poolName = "test-pool" } "test" { datasource.connection.metaData.databaseProductVersion shouldBe "9.6.24" } })
おわり。