きり丸の技術日記

技術・エンジニアのイベント・資格等はこちらにまとめる予定です

データベースのH2を使用してMyBatisの取得・更新のテストを行う(JavaとSpringBoot)

きり丸アドベントカレンダー2020の9記事目です。


今回の記事でMyBatisのテストを行えるようにします。テスト用のスターターが準備されているので、テストのための準備は簡単です。ただし、テストのセットアップは慣れていないと、時間がかかってしまいます。

この記事を参考にサクっと環境構築していただけると幸いです。

H2とは

インメモリで展開できるDB。

メモリ内で展開できると並列実行できるので、総合的にかなり早くなります。実際に、PostgreSQLで実行すると並列実行できずに20分かかっていましたが、H2では4並列の5分でテストが終わるようになりました。

ただしデメリットとして、H2とPostgreSQLは結局DBとしては異なるので、細かい挙動が異なります。ですので、PostgreSQLで動作確認してからテストでH2に逆輸入すると、動かないことがあるのは痛いです。

基本的にテストは毎日何回も実行したいので、早く実行できることはメリットです。ただし、構文に引っかかったときにはH2とPostgreSQLのどちらでも動くようにする必要があるので、かなり苦労します。

ゴール

  • MyBatisのテストを行う
  • H2でテストを行う
  • 設定ファイルの分割を行う

環境

  • Java
    • 15
  • mybatis-spring-boot-starter
    • 2.1.4
  • mybatis-spring-boot-starter-test
    • 2.1.3
  • H2

手順

MyBatisのtestライブラリをインストールする


@MybatisTestsを使用したいので、mybatis-spring-boot-starter-testの最新版2.1.3をテストコンパイル対象にします。@SpringBootTestでもテストできますが、余計なimportしてしまったりするので、@MybatisTestを使うようにしましょう。

ファイル名:build.gradle

dependencies {
    testCompile "org.mybatis.spring.boot:mybatis-spring-boot-starter-test:2.1.3"
}

spring.profilesを使って設定ファイルを分割する


現在は、application.ymlにすべて記載してしまっています。この状態では、非常にテストがしづらい状態になってしまいます。ですので、DBの設定項目とそれ以外に分割しましょう。

spring.profiles.groupを使用すると、設定ファイルから設定ファイルを読み込めます。

ファイル名:application.yml

spring:
  profiles:
    active:
      - local
    group:
      local:
        - database-local
        - common

ファイル名:application-common.yml

spring:
  thymeleaf:
    mode: HTML
mybatis:
  configuration:
    map-underscore-to-camel-case: true

ファイル名:application-database-local.yml

spring:
  datasource:
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://127.0.0.1:5432/postgres
    username: gitpod
    password:

DBのH2を使えるように設定ファイルを作成する


先にH2用の設定ファイルを用意します。特徴的な設定値としては、urlはインメモリでtestdbというデータベース名を指定しています。また、起動モードはPostgreSQLにしています。

また、DB_CLOSE_DELAY=-1を指定すると、接続が切れるたびにデータベースがリセットされることを防ぎます。リセットされてしまうと、実行時間がかかるので、このやり方が良いでしょう。

ファイル名:application-database-h2.yml

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb;MODE=PostgreSQL;DB_CLOSE_DELAY=-1
    username: root
    password: root

テスト時は、src/test/resources/application.ymlを読み込みます。testディレクトリ配下のapplication.ymlに次の設定を記載します。

ファイル名:application.yml

spring:
  profiles:
    active:
      - ut
    group:
      ut:
        - database-local
        - common2

このように設定することで、通常どおり起動した場合はDBの接続先がPotgreSQL、テストではDBの接続先がH2になります。

テストコードを書く


テストクラスに@MybatisTestを指定します。テスト対象クラスをDIしたいので、@Autowiredをテスト対象クラスに付与します。この状態で、JUnit 5でのテストができる状態になりました。

あとは、データ追加のinsertメソッドとデータ取得のfindListメソッドはすでに用意していますので、データ準備にinsertメソッド、検証にfindListメソッドを呼ぶと目的どおりの項目がDBに登録されているかをテストできます。

なお、マスタデータ等のinsertメソッドのコードが無い場合、テストコード内でinsertメソッドを自作する必要があります。

ファイル名:TodoRepositoryTests.java

@MybatisTest // 設定ファイルを読み込んで、目的のクラスをDIできる状態にする
public class TodoRepositoryTests {
  @Autowired // DIする
  TodoRepository todoRepository;

  @DisplayName("insertした結果をfindする") // テストの表示を変更する
  @Test // テスト対象のメソッドを表現する
  public void test_01() {
    // GIVEN 準備
    TodoDto todoDto = TodoDto.builder().id(1).userId("kirimaru").action("豆腐買う").build();
    todoRepository.insert(todoDto);

    // WHEN 実施
    final List<TodoDto> kirimaru = todoRepository.findList("kirimaru");
    // THEN 検証
    assertThat(kirimaru).isEqualTo(
        List.of(todoDto)
    );
  }
}

ソースコード

このタイミングで、登録(Insert)と取得(Select)以外にも、更新(Update)と削除(Delete)も行うようにしています。

アドベントカレンダー9日目。
github.com

終わりに

「DBのテストのセットアップが大変だからやりたくありません!」というのは、今までの経験では受け入れられたことはありません。しかしUIのテストや他の構築が難しいテストに関してはセットアップが大変で、リターンが薄いから実施しないという判断は何度もしてきました。

「やれる」ことは分かっていても「できる」ように環境構築するには壁があります。

手元のSpringの入門書を読み直していますが、なぜかテスト関連の記載はないので、こういう記事で補完していただけると幸いです。


この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。

参考記事

H2:Featuresページ www.h2database.com

PlayFramework:H2データベース
フレームワークは異なりますが、H2の設定値は参考になります) www.playframework.com

類似記事

きり丸アドベントカレンダー2020 adventar.org

きり丸のHerokuページ
https://kirimaru-todoapp.herokuapp.com/

10日目のアドベントカレンダーの記事 https://nainaistar.hatenablog.com/entry/2020/12/10/083000nainaistar.hatenablog.com

f:id:nainaistar:20201109133010p:plain