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
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”.
コメント