How to unit test the data access layer in SpringBoot?

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 OceanBaseso TiDBon 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+ Mybatisas the development framework, and everyone first thinks that they can use SpringBootthe built-in test annotations @SpringBootTestfor 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 mybatishas given us such a solution.

  1. Introduce dependenciesmybatis-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>
  1. Mapper interface
@Mapper
public interface CityMapper {

    @Select("SELECT * FROM CITY WHERE state = #{state}")
    City findByState(@Param("state") String state);

}
  1. 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");
    }

}
  1. 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 @SpringBootApplicationclasses with a in the same package as the test class.

package sample.mybatis.mapper;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
class MapperTestApplication {

}

  1. operation result

For details, refer to github.com/mybatis/spr…

但是, 上面是使用原生mybatis的测试方式,而我们项目用的是基于mybatis封装的开源框架tkMappergithub地址是https://github.com/abel533/Mapper,并不适用啊,无解,只能去看下mybatis-spring-boot-starter-test的原理。

实现原理

实际上mybatis-spring-boot-starter-test的实现原理很简单,代码目录结构如下:

  1. @MybatisTest注解如下,引入MybatisTestContextBootstrapper测试引导程序。同时引入其他的注解,进行自动装配。

  1. @AutoConfigureMybatisMybatisTest注解引入,会去找META-INF下的spring.factories,自动组装mybatis相关的bean

那么基于目前的理解,我们也可以简单实现一个基于TkMapper的测试框架。

Mapper测试框架

我们参照mybatis原生的实现方式

  1. 重新命名,内容不变

  1. 修改spring.factories添加MapperAutoConfiguration

  1. 使用自定义测试注解@MapperTest

虽然这里有insert语句,但是测试结束,数据不会真的插入到表中,因为MapperTest注解上包含了事务注解,所以是可以反复进行测试的。

总结

本文分享了基于springboot+mybatis项目中针对数据访问层进行单元测试的一种方式,这种方式只注入mybatis相关的bean,快速高效的对不同类型的数据库进行测试,保证程序的正确性。

其实,对于大多数据的程序员来说,写单元测试可能是一种负担和累赘,但是如果你的单元测试真的能够在你的项目中有其价值,那么就是值得的,千万不要为了单元测试而单元测试。

欢迎关注个人公众号【JAVA旭阳】交流学习!

Guess you like

Origin juejin.im/post/7257085361260871735