foreword
As a TOB enterprise oriented to banks and financial institutions, our company frequently encounters the transformation needs of localized databases proposed by various Party A fathers, including, , and OceanBase
so TiDB
on geldenDB
. Every adaptation requires a lot of manpower for testing, so is there a more efficient and low-cost way to solve this problem? This article introduces a fast, efficient and reusable solution - unit testing the data access layer.
Mybatis test dependencies
Our project uses SpringBoot
+ Mybatis
as the development framework, and everyone first thinks that they can use SpringBoot
the built-in test annotations @SpringBootTest
for testing. However, one of the biggest disadvantages of using this annotation is that it is necessary to start the entire container and inject all the beans. Then a test is equivalent to starting an application. It takes nearly 70-80 seconds to start our application once, and the day lily is cold .
So is there a better way, is it necessary to inject the full amount of beans? Is it enough to just inject the beans related to the data access layer? In fact, the official mybatis
has given us such a solution.
- Introduce dependencies
mybatis-spring-boot-starter-test
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>2.3.0</version>
<scope>test</scope>
</dependency>
- Mapper interface
@Mapper
public interface CityMapper {
@Select("SELECT * FROM CITY WHERE state = #{state}")
City findByState(@Param("state") String state);
}
- Test class using junit5
// 使用junit5
@MybatisTest
// 使用真实的数据源进行测试
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class CityMapperTest {
@Autowired
private CityMapper cityMapper;
@Test
public void findByStateTest() {
City city = cityMapper.findByState("CA");
assertThat(city.getName()).isEqualTo("San Francisco");
assertThat(city.getState()).isEqualTo("CA");
assertThat(city.getCountry()).isEqualTo("US");
}
}
- Customize a startup class
@MybatisTest
By default @SpringBootApplication
classes with . Therefore, due to bean
some methods defined, some unexpected errors may occur, or some unnecessary components are loaded ApplicationContext
. To avoid this, we can create @SpringBootApplication
classes with a in the same package as the test class.
package sample.mybatis.mapper;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
class MapperTestApplication {
}
- operation result
For details, refer to github.com/mybatis/spr…
但是, 上面是使用原生mybatis的测试方式,而我们项目用的是基于mybatis封装的开源框架tkMapper
,github
地址是https://github.com/abel533/Mapper
,并不适用啊,无解,只能去看下mybatis-spring-boot-starter-test
的原理。
实现原理
实际上mybatis-spring-boot-starter-test
的实现原理很简单,代码目录结构如下:
@MybatisTest
注解如下,引入MybatisTestContextBootstrapper
测试引导程序。同时引入其他的注解,进行自动装配。
@AutoConfigureMybatis
由MybatisTest
注解引入,会去找META-INF
下的spring.factories
,自动组装mybatis相关的bean
那么基于目前的理解,我们也可以简单实现一个基于TkMapper
的测试框架。
Mapper测试框架
我们参照mybatis
原生的实现方式
- 重新命名,内容不变
- 修改
spring.factories
添加MapperAutoConfiguration
- 使用自定义测试注解
@MapperTest
虽然这里有insert
语句,但是测试结束,数据不会真的插入到表中,因为MapperTest
注解上包含了事务注解,所以是可以反复进行测试的。
总结
本文分享了基于springboot+mybatis
项目中针对数据访问层进行单元测试的一种方式,这种方式只注入mybatis相关的bean,快速高效的对不同类型的数据库进行测试,保证程序的正确性。
其实,对于大多数据的程序员来说,写单元测试可能是一种负担和累赘,但是如果你的单元测试真的能够在你的项目中有其价值,那么就是值得的,千万不要为了单元测试而单元测试。
欢迎关注个人公众号【JAVA旭阳】交流学习!