[JAVA] Use DBUnit for Spring Boot test

Abstract

Use dbunit to test your Spring Boot project.

environment

Premise

Test target

column Mold Primary key
person_id integer
person_name character varying(20)
birth_date date
birth_place character varying(20)

I created the following Mapper with MyBatis for the table.

@Mapper
public interface PersonMapper {

	@Select("SELECT * FROM person WHERE person_id = #{personId}")
	public Person selectById(int personId);

	@Insert("INSERT INTO person(person_id, person_name, birth_date, birth_place) VALUES (#{person_id}, #{person_name}, #{birth_date}, #{birth_place})")
	public void insert(Person person);
}

Detailed procedure

Add dependency

Add spring-test-dbunit and dbunit to the dependencies.

pom.xml


<dependency>
  <groupId>com.github.springtestdbunit</groupId>
  <artifactId>spring-test-dbunit</artifactId>
  <version>1.3.0</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.dbunit</groupId>
  <artifactId>dbunit</artifactId>
  <version>2.6.0</version>
  <scope>test</scope>
</dependency>

Prerequisite data input

Describe the data in the DB before executing the test (before executing the test method).

Basic pattern

__ * In the following cases, the data used for the test will be committed __ (The rollback case will be described later)

Input data description

Pattern A.xml


<?xml version="1.0" encoding="UTF-8"?>
<dataset>
	<person person_id="1" person_name="Suzaki" birth_date="1986-12-25" />
	<person person_id="2" person_name="Nishi"                          birth_place="Hyogo prefecture" />
	<person person_id="3"                      birth_date="1994-02-22" birth_place="Tokyo" />
</dataset>
Test class creation
// (1)
@RunWith(SpringRunner.class)
@SpringBootTest
@TestExecutionListeners({
	DependencyInjectionTestExecutionListener.class,
	DbUnitTestExecutionListener.class
})
public class PersonMapperTest {

	@Autowired // (2)
	PersonMapper mapper;

	@Test
	@DatabaseSetup("/dbunit/Pattern A.xml") // (3)
	public void test() {
		//Write test code
	}
}
(1) Write all the above annotations in the test class
(2) Autowired is possible to start Spring
(3) In the test method@DatabaseSetupAnd describe the xml path in its argument
Execution result
# SELECT * FROM person;
person_id | person_name | birth_date | birth_place
-----------+-------------+------------+-------------
        1 | Suzaki      | 1986-12-25 |
        2 | Nishi       |            |Hyogo prefecture
        3 |             | 1994-02-22 |Tokyo
(3 lines)

Blank input pattern

Input data description

If you write one line of tags without attributes as shown below, only DELETE will be executed and the table will be empty.

Pattern B.xml


<?xml version="1.0" encoding="UTF-8"?>
<dataset>
	<person />
</dataset>
Execution result
# SELECT * FROM person;
 person_id | person_name | birth_date | birth_place
-----------+-------------+------------+-------------
(0 line)

Empty string input pattern

Input data description

Pattern C.xml


<?xml version="1.0" encoding="UTF-8"?>
<dataset>
	<person person_id="4" person_name="" birth_date="1991-12-25" birth_place="Hyogo prefecture" />
</dataset>

If the above xml is read only with the basic pattern test code, the following exception will occur. java.lang.IllegalArgumentException: table.column=person.person_name value is empty but must contain a value (to disable this feature check, set DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS to true)

Additional code

Add the following configuration to the path read when running the test.

@Configuration
public class DatasourceConfig {

	// (1)
	@Bean
	public DatabaseConfigBean dbUnitDatabaseConfig() {
		DatabaseConfigBean bean = new DatabaseConfigBean();

		bean.setAllowEmptyFields(true); // (2)

		return bean;
	}

	// (3)
	@Bean
	public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection(
			DatabaseConfigBean dbUnitDatabaseConfig,
			DataSource dataSource
	) {
		DatabaseDataSourceConnectionFactoryBean bean = new DatabaseDataSourceConnectionFactoryBean(dataSource);
		bean.setDatabaseConfig(dbUnitDatabaseConfig);
		return bean;
	}
}
(1) Register the runtime config as a bean
(2) Turn on the switch that allows empty strings(The default is false)
(3) (1)Reflect the setting of to Datasource used in Spring
Execution result
# SELECT * FROM person;
person_id | person_name | birth_date | birth_place
-----------+-------------+------------+-------------
        4 |             | 1991-12-25 |Hyogo prefecture
(1 line)
@Test
@DatabaseSetup("/dbunit/Pattern C.xml")
public void test() {
  Person actual = mapper.selectById(4);
  assertThat(actual.getPerson_name()).isEqualTo(""); // ->success
}

Pattern to return data after testing

Test class creation

Add listeners and annotations to the base pattern.

@RunWith(SpringRunner.class)
@SpringBootTest
@TestExecutionListeners({
	DependencyInjectionTestExecutionListener.class,
	TransactionalTestExecutionListener.class, // (1)
	DbUnitTestExecutionListener.class
})
@Transactional //(2)
public class PersonMapperTest3 {
  ...
}
(1) Add a listener for transaction management
(2) A unit that actually manages transactions(Basically class)so@TransactionalGrant

You can also add @Transactional to the method.

@Test
@Transactional
@DatabaseSetup("/dbunit/Pattern A.xml")
public void test() {
  ...
}

Avoid warning text

When executed with the above pattern, the following log is output at the WARN level. Potential problem found: The configured data type factory 'class org.dbunit.dataset.datatype.DefaultDataTypeFactory' might cause problems with the current database 'PostgreSQL' (e.g. some datatypes may not be supported properly). In rare cases you might see this message because the list of supported database products is incomplete (list=[derby]). If so please request a java-class update via the forums.If you are using your own IDataTypeFactory extending DefaultDataTypeFactory, ensure that you override getValidDbProducts() to specify the supported database products.

Since the log says that DataTypeFactory is not specified, add the following description to the configuration class used in the empty string input pattern.

@Bean
public DatabaseConfigBean dbUnitDatabaseConfig() {
  DatabaseConfigBean bean = new DatabaseConfigBean();

  bean.setAllowEmptyFields(true);
  bean.setDatatypeFactory(new PostgresqlDataTypeFactory()); // (1)

  return bean;
}
(1) Since PostgreSQL is used, the DataTypeFactory for PostgreSQL provided by dbunit is specified.

Assumed data definition

Basic pattern

Assumed data description

Describe in the same format as the prerequisite data. When null or empty string is assumed, it is the same as the prerequisite data input.

Pattern D.xml


<?xml version="1.0" encoding="UTF-8"?>
<dataset>
	<person person_id="1" person_name="Suzaki" birth_date="1986-12-25" />
	<person person_id="2" person_name="Nishi"                          birth_place="Hyogo prefecture" />
	<person person_id="3"                      birth_date="1994-02-22" birth_place="" />
</dataset>

Assumed result 1.xml


<?xml version="1.0" encoding="UTF-8"?>
<dataset>
	<person person_id="1" person_name="Suzaki" birth_date="1986-12-25" />
	<person person_id="2" person_name="Nishi"                          birth_place="Hyogo prefecture" />
	<person person_id="3"                      birth_date="1994-02-22" birth_place="" />
	<person person_id="11" person_name="Uesaka" birth_date="1991-12-19" birth_place="Kanagawa Prefecture" />
</dataset>
Test method creation
@Test
@DatabaseSetup("/dbunit/Pattern D.xml")
@ExpectedDatabase(
	value="/dbunit/Assumed result 1.xml",
	assertionMode=DatabaseAssertionMode.NON_STRICT
) // (1)
public void test() {
	Person param = new Person();
	param.setPerson_id(11);
	param.setPerson_name("Uesaka");
	param.setBirth_date(new Date(91, 11, 19));
	param.setBirth_place("Kanagawa Prefecture");

	mapper.insert(param);
}
(1) Describe the annotation that specifies the expected result. By default all tables are checked, but assertionMode=NON_If STRICT is used, only the table described in xml will be inspected.

Reference site

SpringBoot 45.Testing Spring Framework Unit test implementation method 1-3. Repository test (Junit4, spring-test, DBUnit) │ ヰ Sword toy box How to set default properties in spring dataset DatabaseConfig - Stack Overflow

Recommended Posts

Use DBUnit for Spring Boot test
Use Spring Test + Mockito + JUnit 4 for Spring Boot + Spring Retry unit tests
Spring Boot + Springfox springfox-boot-starter 3.0.0 Use
Use Spring JDBC with Spring Boot
Spring Boot for annotation learning
How to write a unit test for Spring Boot 2
Use Basic Authentication with Spring Boot
Spring Boot for the first time
Frequent annotations for Spring Boot tests
How to use ModelMapper (Spring boot)
Beginning with Spring Boot 0. Use Spring CLI
Let's write a test code for login function in Spring Boot
Perform transaction confirmation test with Spring Boot
Spring Boot @WebMvcTest test enables Spring Security default security
WebMvcConfigurer Memorandum of Understanding for Spring Boot 2.0 (Spring 5)
Use cache with EhCashe 2.x with Spring Boot
Form class validation test with Spring Boot
Challenge Spring Boot
Spring Boot Form
Spring Boot Memorandum
[For internal use] For those assigned to the Spring Boot project (under construction)
gae + spring boot
About designing Spring Boot and unit test environment
Test controller with Mock MVC in Spring Boot
Use Thymeleaf text template mode from Spring Boot
How to use MyBatis2 (iBatis) with Spring Boot 1.4 (Spring 4)
How to use built-in h2db with spring boot
Use Servlet filter in Spring Boot [Spring Boot 1.x, 2.x compatible]
Annotation notes when writing tests for Spring Boot
How to perform UT with Excel as test data with Spring Boot + JUnit5 + DBUnit
Plans to support JDK 11 for Eclipse and Spring Boot
Settings for connecting to MySQL with Spring Boot + Spring JDBC
SPRING BOOT learning record 01
Spring Boot + Heroku Postgres
Spring boot memo writing (1)
[JUnit 5 compatible] Write a test using JUnit 5 with Spring boot 2.2, 2.3
First Spring Boot (DI)
SPRING BOOT learning record 02
[Spring Boot] How to create a project (for beginners)
Spring Boot2 cheat sheet
Customizer for Platform Transaction Manager added from Spring Boot 1.5
Spring Boot exception handling
Spring Boot Servlet mapping
Spring boot development-development environment-
Spring Boot learning procedure
[JUnit 5] Write a validation test with Spring Boot! [Parameterization test]
Learning Spring Boot [Beginning]
Spring boot memo writing (2)
Spring Boot 2.2 Document Summary
Test field-injected class in Spring boot test without using Spring container
[Spring Boot] DataSourceProperties $ DataSourceBeanCreationException
Spring Boot 2.3 Application Availability
Spring boot tutorials Topics
I wrote a test with Spring Boot + JUnit 5 now
File upload with Spring Boot (do not use Multipart File)
Download with Spring Boot
Steps required to issue an asynchronous event for Spring Boot
Change the injection target for each environment with Spring Boot 2
How to call and use API in Java (Spring Boot)
Introductory hands-on for beginners of Spring 5 & Spring Boot 2 has been released
Use thymeleaf3 with parent without specifying spring-boot-starter-parent in Spring Boot