LoginSignup
8
8

More than 5 years have passed since last update.

組み込みMySQLを使ったSpockによるSpringBootのユニットテスト

Last updated at Posted at 2016-10-16

概要

組み込みMySQL(wix-embedded-mysql) をSpringBootTest、Spockと組み合わせて使う際に、少しハマったのでその対応方法。

ハマりどころ

サンプルで動かしてみるところまではうまく行ったが、複数のテストケースを動かそうとするとうまくいかない。
元々やろうとしてたのは下記の通り。

  • 各テストクラスの実行前にMySQLを起動(setupSpec)
  • テスト終了時に停止(cleanupSpec)

ところがこれをやろうとするとクラスが増えるとうまくいかない。
どうも下記のようなところで不都合が出る模様。

  • SpringBoot(Test) 起動と組み込みDBの起動停止の兼ね合い
  • 組み込みDBをテスト実行の中でいつ起動するか停止するかで組み込みDBのプロセス管理を考える必要が出て来る
    • 例えばSpringBootの起動前にDBは立ち上がっている状態にしておかないと、dataSourceやflywayなどのDBマイグレーションが動かない

setupSpecじゃなくてDIコンテナに登録しておくとか、色々試してみたものの、最終的に下記の対応に落ち着いた。

対応

  • 組み込みMySQLインスタンスはテストフェーズの中でひとつにする
  • 全てのテストの中で最初に実行されるテストで起動し、テスト中はそのインスタンスを使い続ける
  • 具体的にはSingleton(staticファクトリーメソッド方式)で組み込みMySQLインスタンス提供するUtilityを用意
  • setupSpecで、そのインスタンスを明示的にロード
    • 最初にロードされた時点で組み込みMySQLが起動し、以降は使いまわされる
    • どのsetupSpecが最初に呼ばれるかは保証されないので全テストクラスに必要
    • setupSpecはSpringBootの起動より前に呼ばれる

サンプル

MySQLインスタンス提供ユーティリティ

public final class EmbeddedTestMysql {

  private EmbeddedTestMysql() {
  }

  // プロジェクトに合わせた組み込みMySQLの設定
  private static final Version VERSION = Version.v5_5_40;
  private static final Charset CHARSET = Charset.UTF8;
  private static final int PORT = 13306;
  private static final String SCHEMA_NAME = "sample";

  private static final MysqldConfig MYSQLD_CONFIG = MysqldConfig.aMysqldConfig(VERSION)
      .withCharset(CHARSET)
      .withPort(PORT)
      .build();

  private static final SchemaConfig SCHEMA_CONFIG = SchemaConfig.aSchemaConfig(SCHEMA_NAME)
      .withCharset(CHARSET)
      .build();

  private static final EmbeddedMysql SINGLETON_INSTANCE = EmbeddedMysql.anEmbeddedMysql(MYSQLD_CONFIG)
      .addSchema(SCHEMA_CONFIG).start();

  // staticファクトリーメソッドによるシングルトンインスタンスを提供
  public static EmbeddedMysql getInstance() {
    return SINGLETON_INSTANCE;
  }

実際のテストクラス

@Unroll
@SpringBootTest
class SampleRepositorySpec extends Specification {

    @Shared
    EmbeddedMysql mysql;

    @Autowired
    DataSource dataSource

    @Autowired
    SampleRepository sampleRepository

    def setupSpec() {
        // Bootの起動より前に呼ばれる
       // 初回にどこのテストが呼ばれるか分からないので、必ず書く
        mysql = EmbeddedTestMysql.getInstance()
    }

    def cleanupSpec() {
        // インスタンスを使いまわすので、mysql.stop()はしない
    }

    def setup() {
        // この時点でDBは起動している
        // Bootも起動している
        // 初期データの登録などが可能
    }

    def "何かしらのテスト"() {
        // データベースが必要なテストを実施      
    }
}

参考

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8