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よりも便利だと思います。
JUnitテスト時のコンソールログにH2に接続されているログが出力されていることが確認できます。
1 |
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' |
参考サイト
https://howtodoinjava.com/spring-boot2/testing/datajpatest-annotation/
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(); // 管理状態をクリア | |
} |
KHI入社して退社。今はCONFRAGEで正社員です。関西で140-170/80~120万から受け付けております^^
得意技はJS(ES6),Java,AWSの大体のリソースです
コメントはやさしくお願いいたします^^
座右の銘は、「狭き門より入れ」「願わくは、我に七難八苦を与えたまえ」です^^