Spring BootのテストでJUnit5+H2+@DataJpaTestアノテーションでテストする方法
リポジトリインタフェースのテストでDBSetup,DBUnitあたりを使うことが多いと思うのですが、H2 + @DataJpaTestアノテーションを使うことによってデーたベースをインメモリにすることができます。
H2 + @DataJpaTestアノテーションのメリットは以下の通りです。
| ライブラリ | メリット | デメリット |
|---|---|---|
| DBSetup | 超流行っている | 各開発者のテストデータによって他の開発者のテストケースが失敗する恐れがある |
| H2 | インメモリデータベースなので閉じられたデータベースでのテストとなる | ネイティブクエリを使用している場合、H2と構文が異なる場合、使えない恐れがある |
build.gradleのdependenciesです。
dependencies {
// 省略
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.2.0'
testImplementation 'org.assertj:assertj-core:3.15.0' // for assertion
testImplementation 'com.h2database:h2:1.4.200' // for in memory database
}
リポジトリクラスのテストコードサンプルです。
package jp.co.confrage.repository;
import java.util.List;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import com.example.demo.primary.entity.EmpUser;
@DataJpaTest
public class EmpUserRepositoryTest {
@Autowired private TestEntityManager em;
@Autowired private EmpUserRepository repository;
@BeforeEach
void beforeEach() { // ここでエンティティクラスを使用してH2にデータ作成する
em.persist(new EmpUser("STOF", 20));
em.persist(new EmpUser("ETHOSENS", 30));
em.persist(new EmpUser("dulcamara", 40));
}
@Test
public void サンプルテスト() {
List list = repository.findByHogehoge();
Assertions.assertThat(list.size()).isEqualTo(3);
}
}
@DataJpaTestアノテーション
テストクラスに対して@DataJpaTestアノテーションをつけます。
これで、インメモリDBの設定をしたり@Entity,@Repositoryアノテーションが付加されたクラスやインタフェースをBean登録されます。
@ExtendWith(SpringExtension.class)アノテーションは、@DataJpaTestアノテーションに含まれているため不要です。
インメモリデータベースを使用することにより、各テストの前処理でtruncateなどの処理が不要になりますのでDBSetupよりも便利だと思います。
また、@DataJpaTestアノテーションは@Transactionalアノテーションを含むため、各テストごとにロールバックしてくれます。
JUnitテスト時のコンソールログにH2に接続されているログが出力されていることが確認できます。
o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database: url='jdbc:h2:mem:d67d43s5-42c0-464e-b78f-7feb1b46f23b;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
参考サイト

PKがサロゲートキーの場合(PostgreSQL)
PKがサロゲートキーでシーケンスオブジェクトで採番している場合、テストのたびにシーケンスオブジェクトを初期化しないと、各テスト間でシーケンスを保持してしまうことになり、独立性が保てなくなります。
PostgreSQLの場合とH2ではシーケンスオブジェクトの初期化が違います。テストの@BeforeEachアノテーションを付与しているメソッドでTestEntityManagerからH2のネイティブクエリを発行する必要があります。
@Autowired private TestEntityManager em;
@BeforeEach
void beforeEach() {
em.getEntityManager()
.createNativeQuery("alter sequence mst_id_seq restart with 1 ") // シーケンスオブジェクト名:mst_id_seq
.executeUpdate(); // シーケンスオブジェクトの採番を初期化
em.clear(); // 管理状態をクリア
}
Entityクラス作成しておく
SQLで使っているテーブルのエンティティは全て作成しておく必要があります。そうでないとリポジトリのテストで、「テーブルが見つかりません」とエラーが出ます。
参考サイト

KHI入社して退社。今はCONFRAGEで正社員です。関西で140-170/80~120万から受け付けております^^
得意技はJS(ES6),Java,AWSの大体のリソースです
コメントはやさしくお願いいたします^^
座右の銘は、「狭き門より入れ」「願わくは、我に七難八苦を与えたまえ」です^^


コメント