SpringBoot中如何對(duì)數(shù)據(jù)訪問層進(jìn)行單元測(cè)試?
前言
我們公司作為一個(gè)面向銀行、金融機(jī)構(gòu)的TO B類企業(yè),頻繁遇到各個(gè)甲方爸爸提出的國(guó)產(chǎn)化數(shù)據(jù)庫(kù)的改造需求,包括OceanBase, TiDB,geldenDB等等。每次適配都需要投入大量的人力進(jìn)行測(cè)試工作,那么有沒有更高效、低成本的方式去解決這個(gè)問題呢?本文就介紹一種快高效、可復(fù)用的解決方案——對(duì)數(shù)據(jù)訪問層做單元測(cè)試。
Mybatis測(cè)試依賴
我們項(xiàng)目采用的SpringBoot + Mybatis作為開發(fā)框架,大家第一想到可以用SpringBoot自帶的測(cè)試注解@SpringBootTest進(jìn)行測(cè)試。但是使用該注解有一個(gè)最大的弊端就是需要啟動(dòng)整個(gè)容器,注入全部的bean,那么一次測(cè)試就相當(dāng)于啟動(dòng)一次應(yīng)用,我們的應(yīng)用啟動(dòng)一次就要花費(fèi)近70~80秒,黃花菜都涼了。
圖片
那么有沒有更好的辦法,有必要注入全量的bean嗎?是不是只要注入數(shù)據(jù)訪問層相關(guān)的bean即可,其實(shí)官方的mybatis就給了我們這樣的的解決方案。
- 引入依賴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接口
@Mapper
public interface CityMapper {
@Select("SELECT * FROM CITY WHERE state = #{state}")
City findByState(@Param("state") String state);
}
- 使用junit5的測(cè)試類
// 使用junit5
@MybatisTest
// 使用真實(shí)的數(shù)據(jù)源進(jìn)行測(cè)試
@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");
}
}
- 自定義一個(gè)啟動(dòng)類
@MybatisTest在默認(rèn)情況下將會(huì)探測(cè)到帶有 @SpringBootApplication的類。因此,由于 bean定義的一些方法,可能會(huì)發(fā)生一些意想不到的錯(cuò)誤,或者一些不必要的組件被裝入 ApplicationContext。為了避免這種情況,我們可以在與測(cè)試類相同的包中創(chuàng)建帶有 @SpringBootApplication 的類。
package sample.mybatis.mapper;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
class MapperTestApplication {
}
圖片
- 運(yùn)行結(jié)果
圖片
詳細(xì)內(nèi)容參考 https://github.com/mybatis/spring-boot-starter/blob/master/mybatis-spring-boot-test-autoconfigure/src/site/zh/markdown/index.md**但是,**上面是使用原生mybatis的測(cè)試方式,而我們項(xiàng)目用的是基于mybatis封裝的開源框架tkMapper,github地址是[https://github.com/abel533/Mapper](https://github.com/abel533/Mapper),并不適用啊,無(wú)解,只能去看下mybatis-spring-boot-starter-test的原理。
實(shí)現(xiàn)原理
實(shí)際上mybatis-spring-boot-starter-test的實(shí)現(xiàn)原理很簡(jiǎn)單,代碼目錄結(jié)構(gòu)如下:
圖片
- @MybatisTest注解如下,引入MybatisTestContextBootstrapper測(cè)試引導(dǎo)程序。同時(shí)引入其他的注解,進(jìn)行自動(dòng)裝配。
圖片
- @AutoConfigureMybatis由MybatisTest注解引入,會(huì)去找META-INF下的spring.factories,自動(dòng)組裝mybatis相關(guān)的bean
圖片
那么基于目前的理解,我們也可以簡(jiǎn)單實(shí)現(xiàn)一個(gè)基于TkMapper的測(cè)試框架。
Mapper測(cè)試框架
我們參照mybatis原生的實(shí)現(xiàn)方式
- 重新命名,內(nèi)容不變
圖片
- 修改spring.factories添加MapperAutoConfiguration
圖片
- 使用自定義測(cè)試注解@MapperTest
圖片
雖然這里有**insert**語(yǔ)句,但是測(cè)試結(jié)束,事務(wù)會(huì)被回滾,數(shù)據(jù)不會(huì)真的插入到表中,所以是可以反復(fù)進(jìn)行測(cè)試的。
圖片
總結(jié)
本文分享了基于springboot+mybatis項(xiàng)目中針對(duì)數(shù)據(jù)訪問層進(jìn)行單元測(cè)試的一種方式,這種方式只注入mybatis相關(guān)的bean,快速高效的對(duì)不同類型的數(shù)據(jù)庫(kù)進(jìn)行測(cè)試,保證程序的正確性。
其實(shí),對(duì)于大多數(shù)據(jù)的程序員來(lái)說(shuō),寫單元測(cè)試可能是一種負(fù)擔(dān)和累贅,但是如果你的單元測(cè)試真的能夠在你的項(xiàng)目中有其價(jià)值,那么就是值得的,千萬(wàn)不要為了單元測(cè)試而單元測(cè)試。