CLOVER🍀

That was when it all began.

Database Riderの実行前にFlywayマイグレーションを行うJUnit 5 Extensionを書いてみる

これは、なにをしたくて書いたもの?

JUnitテスト実行時に、Flywayを組み合わせて使いたいなと思いまして。

よくDatabase Riderを使うので、今回はJUnit 5 ExtensionとしてDatabase Riderの実行前にFlywayマイグレーションを動かすように組み込んで
みたいと思います。

FlywayとJUnitテスト

Spring BootのようにFlywayをサポートしていて、コンテナの起動時に実行してしまうようなものを使ったらいい、では話が終わってしまうので
今回はそのような構成は対象外にします。

Flywayサポートがない状態でもテスト時に実行したい場合は?という話をテーマにしています。

まずはFlyway自体を見ると、Flyway Test Extensionsというものがあるようです。

GitHub - flyway/flyway-test-extensions

なのですが、これはSpring Frameworkと組み合わせて使うことが前提になっているようです。となると、Spring Bootを使ったらいいのではと
やっぱり話が終わってしまうので、これは除外ということで。

となると、Flywayのマイグレーションをテストの実行前に動くようにしたくなるのですが、これにはJUnit 5 Extensionを使おうかなと
思います。@BeforeEachや@BeforeAllで都度書いてもいいのですが、各テストで同じようなことをするならJUnit 5 Extensionとして
書いてもいいかなと。

JUnit 5のExtension Modelを試す - CLOVER🍀

一方で、テストデータの登録やアサーションにはDatabase Riderを使いたいので、Database Riderの実行前にFlywayマイグレーションを
行うようなサンプルがあるかどうか見てみます。

Database Riderのサンプルには、@BeforeAllのタイミングでFlywayマイグレーションを実行するものがありました。

https://github.com/database-rider/database-rider/blob/1.44.0/rider-junit5/src/test/java/com/github/database/rider/junit5/FlywayIt.java

というわけで、FlywayマイグレーションをJUnit 5 Extensionとして組み込み、@BeforeAllのタイミングで実行するようにしてみましょう。

FlywayをJavaコード内に組み込む

そういえば、自分でFlywayマイグレーションをJavaコードから実行したことがありません。Flywayのドキュメントを見てみましょう。

こちらですね。flyway-coreを使います。

API (Java) - Flyway - Product Documentation

また、データベースの種類ごとに追加のライブラリーが必要なようです。今回はMySQLを対象にしましょう。

MySQL - Flyway - Product Documentation

その他のデータベースについては、こちらからたどってください。

Supported Databases - Flyway - Product Documentation

なお、flyway-coreにはデフォルトでH2 Database、SQLite 3、Testcontainersのサポートが入っているようです。それ以外のデータベースに
ついては追加のライブラリーが必要です。

では、試していってみましょう。

環境

今回の環境はこちら。

$ java --version
openjdk 21.0.3 2024-04-16
OpenJDK Runtime Environment (build 21.0.3+9-Ubuntu-1ubuntu122.04.1)
OpenJDK 64-Bit Server VM (build 21.0.3+9-Ubuntu-1ubuntu122.04.1, mixed mode, sharing)


$ mvn --version
Apache Maven 3.9.8 (36645f6c9b5079805ea5009217e36f2cffd34256)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 21.0.3, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-117-generic", arch: "amd64", family: "unix"

MySQLは172.17.0.2で動作しているものとします。

 MySQL  localhost:3306 ssl  practice  SQL > select version();
+-----------+
| version() |
+-----------+
| 8.0.39    |
+-----------+
1 row in set (0.0007 sec)

準備

Maven依存関係など。

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.seasar.doma</groupId>
            <artifactId>doma-core</artifactId>
            <version>2.61.0</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.26.3</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.github.database-rider</groupId>
            <artifactId>rider-junit5</artifactId>
            <version>1.44.0</version>
            <scope>test</scope>
        </dependency>

        <!--
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>10.16.0</version>
            <scope>test</scope>
        </dependency>
        -->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-mysql</artifactId>
            <version>10.16.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.seasar.doma</groupId>
                            <artifactId>doma-processor</artifactId>
                            <version>2.61.0</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

データベースアクセスにはDoma 2を使うことにします。Maven Compiler PluginはDoma 2の設定ですね。

Flywayはflyway-mysqlを依存関係に追加します。flyway-coreはflyway-mysqlから推移的に追加されます。

        <!--
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>10.16.0</version>
            <scope>test</scope>
        </dependency>
        -->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-mysql</artifactId>
            <version>10.16.0</version>
            <scope>test</scope>
        </dependency>

Database Rider。JUnit 5のサポート機能を使います。

        <dependency>
            <groupId>com.github.database-rider</groupId>
            <artifactId>rider-junit5</artifactId>
            <version>1.44.0</version>
            <scope>test</scope>
        </dependency>

ちなみに、rider-junit5が依存しているJUnit 5が現時点で5.7.2と古かったのですが、新しくすると例外になったのでDatabase Riderが依存している
バージョンのJUnit 5を使うことにします…。

https://github.com/database-rider/database-rider/blob/1.44.0/rider-junit5/pom.xml#L13

テスト対象のコードを書く

それでは、まずはテスト対象のコードを書きましょう。

複数のテストコードがあった方がよいかなと思ったので、対象も複数にします。

お題を書籍に。エンティティ。

src/main/java/org/littlewings/databaserider/Book.java

package org.littlewings.databaserider;

import org.seasar.doma.Entity;
import org.seasar.doma.Id;

@Entity
public record Book(
        @Id
        String isbn,
        String title,
        Integer price
) {
}

Doma 2ではエンティティにRecordsを使えるようです。

エンティティクラス — Doma ドキュメント

Dao。

src/main/java/org/littlewings/databaserider/BookDao.java

package org.littlewings.databaserider;

import org.seasar.doma.*;
import org.seasar.doma.jdbc.Result;

import java.util.List;

@Dao
public interface BookDao {
    @Insert
    Result<Book> insert(Book book);

    @Sql("select /*%expand*/* from book where isbn = /* isbn */'dummy'")
    @Select
    Book selectByIsbn(String isbn);

    @Sql("select /*%expand*/* from book order by price desc")
    @Select
    List<Book> selectAllOrderByPriceDesc();

    @Delete
    Result<Book> delete(Book book);
}

人物をお題に。エンティティ。

src/main/java/org/littlewings/databaserider/Person.java

package org.littlewings.databaserider;

import org.seasar.doma.Entity;
import org.seasar.doma.Id;

@Entity
public record Person(
        @Id
        Integer id,
        String firstName,
        String lastName,
        Integer age
) {
}

Dao。

src/main/java/org/littlewings/databaserider/PersonDao.java

package org.littlewings.databaserider;

import org.seasar.doma.*;
import org.seasar.doma.jdbc.Result;

import java.util.List;

@Dao
public interface PersonDao {
    @Insert
    Result<Person> insert(Person person);

    @Sql("select /*%expand*/* from person where id = /* id */0")
    @Select
    Person selectById(Integer id);

    @Sql("select /*%expand*/* from person order by id asc")
    @Select
    List<Person> selectAllOrderByIdAsc();

    @Delete
    Result<Person> delete(Person person);
}

Doma 2のConfigクラス。データベースへの接続情報は、外部から受け取ることにしました。

src/main/java/org/littlewings/databaserider/DomaConfig.java

package org.littlewings.databaserider;

import org.seasar.doma.jdbc.Config;
import org.seasar.doma.jdbc.Naming;
import org.seasar.doma.jdbc.dialect.Dialect;
import org.seasar.doma.jdbc.dialect.MysqlDialect;
import org.seasar.doma.jdbc.tx.LocalTransactionDataSource;
import org.seasar.doma.jdbc.tx.LocalTransactionManager;
import org.seasar.doma.jdbc.tx.TransactionManager;

import javax.sql.DataSource;

public class DomaConfig implements Config {
    private Dialect dialect;

    private LocalTransactionDataSource dataSource;

    private TransactionManager transactionManager;

    public static DomaConfig from(String url, String username, String password) {
        return new DomaConfig(url, username, password);
    }

    private DomaConfig(String url, String username, String password) {
        dialect = new MysqlDialect();
        dataSource = new LocalTransactionDataSource(url, username, password);
        transactionManager = new LocalTransactionManager(dataSource.getLocalTransaction(getJdbcLogger()));
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    @Override
    public Dialect getDialect() {
        return dialect;
    }

    @Override
    public TransactionManager getTransactionManager() {
        return transactionManager;
    }

    @Override
    public Naming getNaming() {
        return Naming.SNAKE_LOWER_CASE;
    }
}

Flywayのマイグレーションはsrc/main/resources側に置くことにします。

src/main/resources/db/migration/V1__create_book_table.sql

create table book (
  isbn varchar(14),
  title varchar(255),
  price int,
  primary key(isbn)
);

src/main/resources/db/migration/V2__create_person_table.sql

create table person (
  id int,
  first_name varchar(255),
  last_name varchar(255),
  age int,
  primary key(id)
);

Flywayのマイグレーションの配置先は、デフォルトでクラスパス上のdb/migrationのようなのでそれに合わせたいと思います。

Configuration - flyway-core 10.16.0 javadoc

テストコードを書く

では、テストコードを書いていきます。

まずはDatabase Riderの設定ファイル。

src/test/resources/dbunit.yml

cacheConnection: false
properties:
  caseSensitiveTableNames: true
connectionConfig:
  url: "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin"
  user: "kazuhira"
  password: "password"

書籍のテストデータセットアップ用のデータセット。

src/test/resources/dataset/bookSetup.yml

book:
  - isbn: "978-4798161488"
    title: "MySQL徹底入門 第4版 MySQL 8.0対応"
    price: 4180
  - isbn: "978-4297141844"
    title: "MySQL運用・管理[実践]入門 〜安全かつ高速にデータを扱う内部構造・動作原理を学ぶ"
    price: 3080
  - isbn: "978-4621303252"
    title: "Effective Java 第3版"
    price: 4400

書籍のアサーション用のデータセット。

src/test/resources/dataset/bookExpected.yml

book:
  - isbn: "978-4798161488"
    title: "MySQL徹底入門 第4版 MySQL 8.0対応"
    price: 4180
  - isbn: "978-4297141844"
    title: "MySQL運用・管理[実践]入門 〜安全かつ高速にデータを扱う内部構造・動作原理を学ぶ"
    price: 3080
  - isbn: "978-4621303252"
    title: "Effective Java 第3版"
    price: 4400
  - isbn: "978-4839981723"
    title: "単体テストの考え方/使い方"
    price: 4488

こちらを使ったテストコード。

src/test/java/org/littlewings/databaserider/BookDaoTest.java

package org.littlewings.databaserider;

import com.github.database.rider.core.api.dataset.DataSet;
import com.github.database.rider.core.api.dataset.ExpectedDataSet;
import com.github.database.rider.junit5.api.DBRider;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

@DBRider
class BookDaoTest {
    private DomaConfig config = DomaConfig.from(
            "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin",
            "kazuhira",
            "password"
    );

    private BookDao bookDao = new BookDaoImpl(config);

    @Test
    @DataSet("dataset/bookSetup.yml")
    void select() {
        config
                .getTransactionManager()
                .required(() -> {
                    Book book = bookDao.selectByIsbn("978-4798161488");
                    assertThat(book.title()).isEqualTo("MySQL徹底入門 第4版 MySQL 8.0対応");

                    assertThat(bookDao.selectAllOrderByPriceDesc()).hasSize(3);
                });
    }

    @Test
    @DataSet("dataset/bookSetup.yml")
    @ExpectedDataSet(value = "dataset/bookExpected.yml", orderBy = "isbn")
    void insert() {
        config
                .getTransactionManager()
                .required(() -> {
                    Book book = new Book(
                            "978-4839981723",
                            "単体テストの考え方/使い方",
                            4488
                    );
                    bookDao.insert(book);
                });
    }
}

複数のテストメソッドがあった方がいいかなと思ったくらいで、実装自体はとても単純です。

データベースの接続情報をハードコードしているのは、今回は置いておきます…。

    private DomaConfig config = DomaConfig.from(
            "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin",
            "kazuhira",
            "password"
    );

で、このテスト実行前にFlywayマイグレーションを実行したいところです。またDatabase Riderと同じ接続情報を使いたいところです。

というわけで、今回はこんなJUnit 5 Extensionを作成。@BeforeAllのタイミングでFlywayマイグレーションを実行します。

src/test/java/org/littlewings/databaserider/FlywayExtension.java

package org.littlewings.databaserider;

import com.github.database.rider.core.configuration.ConnectionConfig;
import com.github.database.rider.core.configuration.DBUnitConfig;
import org.flywaydb.core.Flyway;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class FlywayExtension implements BeforeAllCallback {
    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        DBUnitConfig dbUnitConfig = DBUnitConfig.fromGlobalConfig();
        ConnectionConfig connectionConfig = dbUnitConfig.getConnectionConfig();

        Flyway flyway = Flyway
                .configure()
                .dataSource(connectionConfig.getUrl(), connectionConfig.getUser(), connectionConfig.getPassword())
                .load();

        flyway.migrate();
    }
}

Database Riderの設定情報は、DBUnitConfigから取得しています。

せっかくなのでメタアノテーションも作っておきましょう。

src/test/java/org/littlewings/databaserider/FlywayMigration.java

package org.littlewings.databaserider;

import org.junit.jupiter.api.extension.ExtendWith;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(FlywayExtension.class)
public @interface FlywayMigration {
}

これを先ほどのクラスに付与します。

@FlywayMigration
@DBRider
class BookDaoTest {

人物の方もテストを用意しましょう。

テストデータセットアップ用のデータセット。

src/test/resources/dataset/personSetup.yml

person:
  - id: 1
    first_name: "サザエ"
    last_name: "フグ田"
    age: 24
  - id: 2
    first_name: "マスオ"
    last_name: "フグ田"
    age: 28

アサーション用のデータセット。

src/test/resources/dataset/personExpected.yml

person:
  - id: 1
    first_name: "サザエ"
    last_name: "フグ田"
    age: 24
  - id: 2
    first_name: "マスオ"
    last_name: "フグ田"
    age: 28
  - id: 3
    first_name: "カツオ"
    last_name: "磯野"
    age: 11

テストコード。

src/test/java/org/littlewings/databaserider/PersonDaoTest.java

package org.littlewings.databaserider;

import com.github.database.rider.core.api.dataset.DataSet;
import com.github.database.rider.core.api.dataset.ExpectedDataSet;
import com.github.database.rider.junit5.api.DBRider;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

@FlywayMigration
@DBRider
class PersonDaoTest {
    private DomaConfig config = DomaConfig.from(
            "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin",
            "kazuhira",
            "password"
    );

    private PersonDao personDao = new PersonDaoImpl(config);

    @Test
    @DataSet("dataset/personSetup.yml")
    void select() {
        config
                .getTransactionManager()
                .required(() -> {
                    Person person = personDao.selectById(1);
                    assertThat(person.firstName()).isEqualTo("サザエ");
                    assertThat(person.lastName()).isEqualTo("フグ田");

                    assertThat(personDao.selectAllOrderByIdAsc()).hasSize(2);
                });
    }

    @Test
    @DataSet("dataset/personSetup.yml")
    @ExpectedDataSet(value = "dataset/personExpected.yml", orderBy = "id")
    void insert() {
        config
                .getTransactionManager()
                .required(() -> {
                    Person person = new Person(3, "カツオ", "磯野", 11);
                    personDao.insert(person);
                });
    }
}

準備ができたので、テストを実行しましょう。

$ mvn test

最初に実行されたテストクラスの時にFlywayマイグレーションが実行されました。

[INFO] Running org.littlewings.databaserider.BookDaoTest
7月 28, 2024 10:23:11 午後 org.flywaydb.core.FlywayExecutor execute
情報: Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
7月 28, 2024 10:23:11 午後 org.flywaydb.core.internal.schemahistory.JdbcTableSchemaHistory allAppliedMigrations
情報: Schema history table `practice`.`flyway_schema_history` does not exist yet
7月 28, 2024 10:23:11 午後 org.flywaydb.core.internal.command.DbValidate validate
情報: Successfully validated 2 migrations (execution time 00:00.028s)
7月 28, 2024 10:23:11 午後 org.flywaydb.core.internal.schemahistory.JdbcTableSchemaHistory create
情報: Creating Schema History table `practice`.`flyway_schema_history` ...
7月 28, 2024 10:23:12 午後 org.flywaydb.core.internal.command.DbMigrate migrateGroup
情報: Current version of schema `practice`: << Empty Schema >>
7月 28, 2024 10:23:12 午後 org.flywaydb.core.internal.command.DbMigrate doMigrateGroup
情報: Migrating schema `practice` to version "1 - create book table"
7月 28, 2024 10:23:12 午後 org.flywaydb.core.internal.command.DbMigrate doMigrateGroup
情報: Migrating schema `practice` to version "2 - create person table"
7月 28, 2024 10:23:12 午後 org.flywaydb.core.internal.command.DbMigrate logSummary
情報: Successfully applied 2 migrations to schema `practice`, now at version v2 (execution time 00:00.264s)

次のテストクラスの実行時には、すでにFlywayマイグレーションは実行済みなことが表示されます。

[INFO] Running org.littlewings.databaserider.PersonDaoTest
7月 28, 2024 10:23:13 午後 org.flywaydb.core.FlywayExecutor execute
情報: Database: jdbc:mysql://172.17.0.2:3306/practice (MySQL 8.0)
7月 28, 2024 10:23:13 午後 org.flywaydb.core.internal.command.DbValidate validate
情報: Successfully validated 2 migrations (execution time 00:00.010s)
7月 28, 2024 10:23:13 午後 org.flywaydb.core.internal.command.DbMigrate migrateGroup
情報: Current version of schema `practice`: 2
7月 28, 2024 10:23:13 午後 org.flywaydb.core.internal.command.DbMigrate logSummary
情報: Schema `practice` is up to date. No migration necessary.

というわけで、Database Riderの実行前にFlywayマイグレーションを実行するようなJUnit 5 Extensionを書けました。OKですね。

オマケ: Database Riderのデータベースアクセス先をテストコードから設定する

今回はFlywayのデータベースアクセス先をDatabase Riderの設定に寄せましたが、テストコードで使う接続情報をDatabase Riderに
指定したい時もあるような気がします。

こういう時はConnectionHolderというものを使えばよさそうです。

Database Rider / JUnit 5

テストクラスのフィールドに定義しておくと、親クラスまで含めて探してくれるみたいですね。

https://github.com/database-rider/database-rider/blob/1.44.0/rider-junit5/src/main/java/com/github/database/rider/junit5/jdbc/ConnectionManager.java#L87-L128

Database Riderの設定ファイルからは、データベース接続先の情報をコメントアウトします。

src/test/resources/dbunit.yml

cacheConnection: false
properties:
  caseSensitiveTableNames: true
# connectionConfig:
#   url: "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin"
#   user: "kazuhira"
#   password: "password"

テストクラスにConnectionHolder型のフィールドを定義し、これはDoma 2のConfigからJDBCのConnectionを取得するようにします。

src/test/java/org/littlewings/databaserider/BookDaoTest.java

package org.littlewings.databaserider;

import com.github.database.rider.core.api.connection.ConnectionHolder;
import com.github.database.rider.core.api.dataset.DataSet;
import com.github.database.rider.core.api.dataset.ExpectedDataSet;
import com.github.database.rider.junit5.api.DBRider;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

@FlywayMigration
@DBRider
class BookDaoTest {
    private DomaConfig config = DomaConfig.from(
            "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin",
            "kazuhira",
            "password"
    );

    private ConnectionHolder connectionHolder = () -> config.getDataSource().getConnection();

    private BookDao bookDao = new BookDaoImpl(config);

    〜テストメソッドは省略〜
}

もうひとつのテストクラスも同様に。

src/test/java/org/littlewings/databaserider/PersonDaoTest.java

package org.littlewings.databaserider;

import com.github.database.rider.core.api.connection.ConnectionHolder;
import com.github.database.rider.core.api.dataset.DataSet;
import com.github.database.rider.core.api.dataset.ExpectedDataSet;
import com.github.database.rider.junit5.api.DBRider;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

@FlywayMigration
@DBRider
class PersonDaoTest {
    private DomaConfig config = DomaConfig.from(
            "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin",
            "kazuhira",
            "password"
    );

    private ConnectionHolder connectionHolder = () -> config.getDataSource().getConnection();

    private PersonDao personDao = new PersonDaoImpl(config);

    〜テストメソッドは省略〜
}

Flyway用のJUnit 5 Extensionの方は…仕方がないので今回はハードコードにしました…。

src/test/java/org/littlewings/databaserider/FlywayExtension.java

package org.littlewings.databaserider;

import com.github.database.rider.core.configuration.ConnectionConfig;
import com.github.database.rider.core.configuration.DBUnitConfig;
import org.flywaydb.core.Flyway;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class FlywayExtension implements BeforeAllCallback {
    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        /*
        DBUnitConfig dbUnitConfig = DBUnitConfig.fromGlobalConfig();
        ConnectionConfig connectionConfig = dbUnitConfig.getConnectionConfig();
         */

        Flyway flyway = Flyway
                .configure()
                //.dataSource(connectionConfig.getUrl(), connectionConfig.getUser(), connectionConfig.getPassword())
                .dataSource(
                        "jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin",
                        "kazuhira",
                        "password"
                )
                .load();

        flyway.migrate();
    }
}

アプリケーションやテストコードの設定から取るようにしたいですね、このあたりは。

テスト実行時にFlywayマイグレーションが実行される様子は先ほどと同じなので、省略します。

おわりに

Database Riderの実行前にFlywayマイグレーションを行うJUnit 5 Extensionを書いてみました。

Flyway自体をサポートしているフレームワークなどを使ってそちらに任せるようなことが多いような気はしますが、ちょっとした小ネタ的に
押さえておいてもいいのかな、と思います。

そういった環境以外でFlywayを使う時のアイデアのひとつとして。