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の大体のリソースです
コメントはやさしくお願いいたします^^
座右の銘は、「狭き門より入れ」「願わくは、我に七難八苦を与えたまえ」です^^
コメント