使用Spring Boot + Doma2 + Junit5 + DBUnit来正确执行测试数据的回滚
首先
我之前被同事告知说,在之前的测试中,使用这个组合无法成功进行回滚。当时我通过使用Junit4解决了这个问题。然而,现在我再次遇到了相同的组合,并且有时间来解决,所以我努力解决了这个问题,并做了一些备忘录。
环境
“`
Java 11.0.3
Spring Boot 2.2.0.M4
doma-spring-boot-starter 1.1.0
spring-test-dbunit 1.3.0
dbunit 2.6.0
Java 11.0.3
Spring Boot 2.2.0.M4
doma-spring-boot-starter 1.1.0
spring-test-dbunit 1.3.0
dbunit 2.6.0
Java 11.0.3
Spring Boot 2.2.0.M4
doma-spring-boot-starter 1.1.0
spring-test-dbunit 1.3.0
dbunit 2.6.0
Java 11.0.3
Spring Boot 2.2.0.M4
doma-spring-boot-starter 1.1.0
spring-test-dbunit 1.3.0
dbunit 2.6.0
“`
数据库使用的是MariaDB,但我认为其他关系型数据库也应该没有问题(未经验证)。
pom.xml的中文释义是“项目对象模型”。
我会在这里列出必要的依赖关系。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.seasar.doma.boot</groupId>
<artifactId>doma-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<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>
</dependencies>
准备写测试代码之前
因为需要创建一些Bean,所以我会写代码。
为了能够在Spring端管理第三方数据库的事务,将TransactionAwareDataSourceProxy设置为数据源。
因为我希望这个适应于正常启动的情况,所以我会将其写在主要的部分。
@Configuration
public class DatabaseConfig {
@Bean
public DataSource dataSource(DataSourceProperties dataSourceProperties) {
DriverManagerDataSource dataSource = new DriverManagerDataSource(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword());
dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
dataSource.setSchema(dataSource.getSchema());
return new TransactionAwareDataSourceProxy(dataSource);
}
}
由于需要写Dao和Entity,所以我们将根据用于测试的表来进行实现。实际上我们使用了Doma-gen,但由于不相关,所以此次不详述。
import org.seasar.doma.Column;
import org.seasar.doma.Entity;
import org.seasar.doma.GeneratedValue;
import org.seasar.doma.GenerationType;
import org.seasar.doma.Id;
import org.seasar.doma.Table;
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return role;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.Optional;
import org.seasar.doma.Dao;
import org.seasar.doma.Delete;
import org.seasar.doma.Insert;
import org.seasar.doma.Select;
import org.seasar.doma.Update;
import org.seasar.doma.boot.ConfigAutowireable;
import com.tasogarei.User;
@Dao
@ConfigAutowireable
public interface UserDao {
@Select
Optional<User> selectById(Long id);
@Insert
int insert(MUser entity);
@Update
int update(User entity);
@Delete
int delete(User entity);
}
对于Doma的情况,还需要一个SQL文件(这也是由Doma-gen自动生成的)。请在/src/mainresources/META-INF/目录下,按照包名创建文件夹,并将SQL文件放在其中。
select
*
from
user
where
id = /* id */1
此外,由于本次需要从XLSX文件中读取测试数据,所以我正在创建一个可以在Excel中读取的数据。由于繁琐的原因,我会在此省略有关文件的部分。
写测试代码
由于准备工作已经完成,我将开始编写测试。
本次测试将直接调用DAO并验证其结果。
在配置上基本上和Spring Boot + Junit5的设置几乎没有什么不同。
唯一有所变化的地方可能就是@TestExecutionListeners了吧。
如果要将数据输入Excel文件,则需要使用@DbUnitConfiguration。
关于其内容,请参考这里的实现。
只需在测试方法中添加@DatabaseSetup并编写指向文件的加载即可。 classpath指向/src/test/resources。
import static org.junit.jupiter.api.Assertions.*;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;
import com.github.springtestdbunit.TransactionDbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import com.tasogarei.UserDao;
import com.tasogarei.User;
import com.tasogarei.XlsDataSetLoader;
@ExtendWith(SpringExtension.class)
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionDbUnitTestExecutionListener.class
})
@DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class)
@Transactional
public class DBUnitTest {
@Autowired
private UserDao userDao;
@Test
@DatabaseSetup("classpath:dataset/demo-test.xlsx")
public void test() {
Optional<User> user = userDao.selectById(2L);
assertTrue(user.isPresent());
}
}
结束
我写完后并没有做什么特别的设置,但为了下次使用时不感到困扰而留下来。
现在虽然在使用Doma,但因为很麻烦所以不太想使用。