How to test with JUnit5+H2+@DataJpaTest annotation in Spring Boot testing

How to test with JUnit5+H2+@DataJpaTest annotation in Spring Boot testing

I think we often use around DBSetup,DBUnit for testing repository interface, but by using H2 + @DataJpaTest annotation, we can make the database in-memory.

The advantages of the H2 + @DataJpaTest annotation are as follows

Libraries Merits Demerits
DBSetup It’s super trendy. Each developer’s test data could cause other developers’ test cases to fail
H2 In-memory database, so it is a closed database test. If native query is used, may not be usable if syntax is different from H2

build.gradleのdependencies.

dependencies {
  // omission
  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
}

Sample test code for the repository class.

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() { // Create data in H2 using entity classes here
    em.persist(new EmpUser("STOF", 20));
    em.persist(new EmpUser("ETHOSENS", 30));
    em.persist(new EmpUser("dulcamara", 40));
  }

  @Test
  public void sample_test() {
    List list = repository.findByHogehoge();
    Assertions.assertThat(list.size()).isEqualTo(3);
  }
}

@DataJpaTest annotation

Attach the @DataJpaTest annotation to the test class.

This will configure the in-memory DB settings and register the classes and interfaces with @Entity and @Repository annotations to the bean.

The @ExtendWith(SpringExtension.class) annotation is not necessary because it is included in the @DataJpaTest annotation.

Using an in-memory database is more convenient than DBSetup because it eliminates the need for processing such as truncate in the preprocessing of each test.

You can confirm that the log connected to H2 is output to the console log during JUnit testing.

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'

Reference Site

Spring Boot @DataJpaTest - Testing JPA @Repository
Learn about Spring Boot @DataJpaTest annotation and how to use it for testing JPA repositories using TestEntityManager a...

When PK is a surrogate key (PostgreSQL)

If PKs are numbered in a sequence object with a surrogate key, the sequence object must be initialized for each test, or else the sequence will be retained between each test, and independence will not be maintained.

The initialization of sequence objects is different in H2 than in PostgreSQL.

You need to issue a native query for H2 from TestEntityManager in a method that is annotated with the @BeforeEach annotation of the test.

@Autowired private TestEntityManager em;

@BeforeEach
void beforeEach() {
  em.getEntityManager()
    .createNativeQuery("alter sequence mst_id_seq restart with 1 ") // sequence object name:mst_id_seq
    .executeUpdate(); // Initialize sequence object numbering
  em.clear(); // Clear administrative status
}

Create Entity class.

All entities for tables used in SQL must be created. Otherwise, the repository test will give an error “Table not found”.

コメント

タイトルとURLをコピーしました