基本形
以降の記述は以下の基本形をベースに進めていく。
build.gradle
plugins { id 'java' id 'org.springframework.boot' version '3.3.0' id 'io.spring.dependency-management' version '1.1.5' } group = 'com.example' version = '0.0.1-SNAPSHOT' java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-jdbc' runtimeOnly 'com.oracle.database.jdbc:ojdbc11' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-testcontainers' testImplementation 'org.testcontainers:junit-jupiter' testImplementation 'org.testcontainers:oracle-xe' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { useJUnitPlatform() }
import javax.sql.DataSource; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; import org.springframework.jdbc.core.simple.JdbcClient; import org.testcontainers.containers.OracleContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @SpringBootTest @Testcontainers class IntegrationTestSimple { @Container @ServiceConnection static OracleContainer oracle = new OracleContainer("gvenzl/oracle-xe:21.3.0-slim-faststart"); @Autowired DataSource ds; @Test void test() { Integer v = JdbcClient.create(ds).sql("select 1 from dual").query(Integer.class).single(); System.out.println(v); } }
以下は挙動確認用のsrc\test\resources\logback-test.xml
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT"/> </root> <logger name="org.testcontainers" level="DEBUG"/> <!-- The following logger can be used for containers logs since 1.18.0 --> <logger name="tc" level="INFO"/> <logger name="com.github.dockerjava" level="WARN"/> <logger name="com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.wire" level="OFF"/> </configuration>
Initialization scripts
詳細は https://hub.docker.com/r/gvenzl/oracle-xe のInitialization scriptsにある。
コンテナの /container-entrypoint-initdb.d
ディレクトリに*.sql
や*.sh
を配置するとDB起動時にそれらを自動的に実行する。次に、TestcontainersのOracleContainer#withCopyFileToContainer
などでホストのファイルをコンテナの任意ディレクトリにコピーできる。これらを組み合わせて初期化SQLの実行を実現する。
以下例はクラスパスのsql
ディレクトリ(src\test\resources\sql
)を/container-entrypoint-initdb.d
としてコピーする。
import org.testcontainers.utility.MountableFile; @Container @ServiceConnection static OracleContainer oracle = new OracleContainer("gvenzl/oracle-xe:21.3.0-slim-faststart") .withCopyFileToContainer( MountableFile.forClasspathResource("sql"), "/container-entrypoint-initdb.d");
以下例はファイルシステムのパスを使用する場合。また、ファイルの実行順はアルファベット順なので、これを制御したい場合は例えばprefixに001_
, 002_
を付与するのがオススメ、と公式ドキュメントにある。
@Container @ServiceConnection static OracleContainer oracle = new OracleContainer("gvenzl/oracle-xe:21.3.0-slim-faststart") .withCopyFileToContainer( MountableFile.forHostPath(Paths.get("C:\\sample\\sql\\create_tablespace.sql")), "/container-entrypoint-initdb.d/001_init.sql") .withCopyFileToContainer( MountableFile.forHostPath(Paths.get("C:\\sample\\sql\\create_table.sql")), "/container-entrypoint-initdb.d/002_init.sql");
これらスクリプトの実行はSYS
としてXE
インスタンスにSQL*Plusを介して実行される。
Oracle XEでアプリケーションが基本的に使用するのはXEPDB1
なので、これら初期化スクリプトは以下のようにPDBに切り替えてから、がほとんどになると思われる。
alter session set container = XEPDB1;
Startup scripts
詳細は https://hub.docker.com/r/gvenzl/oracle-xe のStartup scriptsにある。
使用方法はInitialization scriptsとほぼ同じでターゲットディレクトリが異なり/container-entrypoint-startdb.d
となる。スクリプトの実行タイミングが異なり大雑把にはInitialization -> Startup の順で、前者がAfter the database setup is completed,
、後者がAfter the database is up and ready for requests,
との記述がある。
withInitScript
上述まではdockerの機能で、これはOracleContainer
(の親クラスのJdbcDatabaseContainer
)の機能。コンテナ起動後にクラスパス下のSQLを実行する。DB接続は自分自身つまりOracleContainer
の設定を使用する。
以下例はsrc\test\resources\create_table.sql
を実行する。
@Container @ServiceConnection static OracleContainer oracle = new OracleContainer("gvenzl/oracle-xe:21.3.0-slim-faststart") .withInitScript("create_table.sql") ;
該当箇所のログは以下のとおり。DATABASE IS READY TO USE!
-> Container is started
のあと、かつ、spring-bootの起動開始前にSQLが実行されているのが分かる。
DEBUG org.testcontainers.containers.output.WaitingConsumer - STDOUT: ######################### DEBUG org.testcontainers.containers.output.WaitingConsumer - STDOUT: DATABASE IS READY TO USE! INFO tc.gvenzl/oracle-xe:21.3.0-slim-faststart - Container gvenzl/oracle-xe:21.3.0-slim-faststart started in PT14.390841S INFO tc.gvenzl/oracle-xe:21.3.0-slim-faststart - Container is started (JDBC URL: jdbc:oracle:thin:@localhost:32776/xepdb1) INFO org.testcontainers.ext.ScriptUtils - Executing database script from create_table.sql (略) INFO (略) - Starting IntegrationTest using Java 17.0.9 with ..(略)
spring-bootの各種DB初期化機能
詳細は省略するが @Sql
とか色々ある。各テストケースに必要なデータ投入はこちら、のような使い分けをすると思われる。
参考URL
- https://hub.docker.com/r/gvenzl/oracle-xe - Testcontainersで使用するoracleのイメージ。
- https://hub.docker.com/r/gvenzl/oracle-free - このエントリでは未使用だが23c以降のイメージはこちら。
- https://testcontainers.com/
- https://java.testcontainers.org/supported_docker_environment/logging_config/ - logbackについて