目录html
本文主要介绍单元测试、集成测试相关的概念、技术实现以及最佳实践。java
本文的demo是基于Java语言,Spring Boot构建的web应用。测试框架使用Junit,模拟框架使用mockito。mysql
以前曾经总结过一篇文章:基于spring-boot的应用程序的单元测试方案,可是当时只是从技术实现的角度去研究单元测试,不少概念没有搞清楚。本文在从新梳理脉络,丰富概念的基础上,整合了前文的大部份内容,可是有一部分几乎在实践中用不到的内容就被删去了。git
在个人我的wiki站点,能够得到更好的阅读体验喔:基于spring-boot的应用程序的单元+集成测试方案程序员
测试领域有不少场景,好比单元测试,集成测试,系统测试,冒烟测试,回归测试,端到端测试,功能测试等。测试的分类方式各有不一样,一些测试场景也可能存在重叠。具体这些场景的概念和区别,你们能够阅读文末给出的参考资料。github
这里主要以程序员的视角谈一下我理解的单元测试和集成测试。web
单元测试是编写单元测试类,针对类级别的测试。好比使用Junit框架,针对一个类,写一个测试类,测试目标类的大部分主要方法。redis
须要注意单元测试的级别是类。项目当中,类之间的依赖调用是很常见的事,若是你要测试一个类,而这个目标类又调用了另外一个类,那么在测试时就没有遵照“在一个类范围内进行测试”,天然算不得单元测试。spring
如上图所示,假设A,B,C,D四个类之间存在上述的依赖关系,咱们要测试类A,那么如何遵照“在类A的范围内测试”?sql
这就是模拟框架要解决的问题了,经过模拟B和C,咱们能够在测试A的时候,调用B和C的模拟对象,而不是实际的B和C。下文会有详细介绍。
若是在测试时超脱一个类的范围,那就能够称为集成测试。如上图所示,你能够测试类A,它会直接或间接调用其余三个类,这就能够叫作集成测试。若是你去测试类C,由于它会调用D,也能够称为集成测试。
若是纯粹按照单元测试的概念,把这个工做代入到一个大型的项目,成百上千的类须要编写测试类,并且类之间的依赖须要编写模拟代码。这样的工做太过庞大,对项目来讲应该是得不偿失的。
我推荐的作法是识别核心代码,或者说是重要的代码,只对这些代码作精细的单元测试。除此以外,都经过集成测试来覆盖。集成测试时优先从最顶层开始,让测试天然流下来。而后根据代码测试覆盖报告,再进行补刀。
此处介绍的mock和stub,是做者基于mockito框架的理解,行业内对这两个概念的定义和此处的理解可能有所出入。做者不追求对概念有“专业的定义”或者“精确的定义”,若是读者有此追求,可另外查阅其余资料。
上文讲到,在作单元测试的时候,须要屏蔽目标类的依赖,mock和stub就是这种操做涉及到的两个概念。
在项目代码中,常常会涉及依赖多个外部资源的状况,好比数据库、微服务中的其余服务。这表示在测试的时候须要先作不少准备工做,好比准备数据库环境,好比先把依赖的服务run起来。
另外,还须要考虑消除测试的反作用,以使测试具有幂等性。好比若是测试会修改数据库,那么是否会影响二次测试的结果,或者影响整个测试环境?
对外部的资源依赖进行模拟,是一个有效的解决方案。即测试时不是真正的操做外部资源,而是经过自定义的代码进行模拟操做。咱们能够对任何的依赖进行模拟,从而使测试的行为不须要任何准备工做或者不具有任何反作用。
在这个大环境下,能够解释mock和stub的含义。当咱们在测试时,若是只关心某个操做是否执行过,而不关心这个操做的具体行为,这种技术称为mock。
好比咱们测试的代码会执行发送邮件的操做,咱们对这个操做进行mock;测试的时候咱们只关心是否调用了发送邮件的操做,而不关心邮件是否确实发送出去了。
另外一种状况,当咱们关心操做的具体行为,或者操做的返回结果的时候,咱们经过执行预设的操做来代替目标操做,或者返回预设的结果做为目标操做的返回结果。这种对操做的模拟行为称为stub(打桩)。
好比咱们测试代码的异常处理机制是否正常,咱们能够对某处代码进行stub,让它抛出异常。再好比咱们测试的代码须要向数据库插入一条数据,咱们能够对插入数据的代码进行stub,让它始终返回1,表示数据插入成功。
当咱们进行单元测试的时候,咱们但愿在spring容器中只实例化测试目标类的实例。
假设咱们的测试目标以下:
@Service public class CityService { @Autowired private CityMapper cityMapper; public List<City> getAllCities() { return cityMapper.selectAllCities(); } public void save(City city) { cityMapper.insert(city); } }
咱们能够这样编写测试类:
@RunWith(SpringRunner.class) @SpringBootTest public class CityServiceUnitTest { @SpringBootApplication(scanBasePackages = "com.shouzheng.demo.web") static class InnerConfig { } @Autowired private CityService cityService; @MockBean private CityMapper cityMapper; @Test public void testInsert() { City city = new City(); cityMapper.insert(city); Mockito.verify(cityMapper).insert(city); } @Test public void getAllCities() { City city = new City(); city.setId(1L); city.setName("杭州"); city.setState("浙江"); city.setCountry("CN"); Mockito.when(cityMapper.selectAllCities()) .thenReturn(Collections.singletonList(city)); List<City> result = cityService.getAllCities(); Assertions.assertThat(result.size()).isEqualTo(1); Assertions.assertThat(result.get(0).getName()).isEqualTo("杭州"); } }
@RunWith
注解声明测试是在spring环境下运行的,这样就能够启用Spring的相关支持。
@SpringBootTest
注解负责扫描配置来构建测试用的Spring上下文环境。它默认搜索@SpringBootConfiguration
类,除非咱们经过classes属性指定配置类,或者经过自定义内嵌的@Configuration
类来指定配置。如上面的代码,就是经过内嵌类来自定义配置。
@SpringBootApplication
扩展自@Configuration
,其scanBasePackages属性指定了扫描的根路径。确保测试目标类在这个路径下,并且须要明白这个路径下的全部bean都会被实例化。虽然咱们已经尽量的缩小了实例化的范围,可是咱们没有避免其余无关类的实例化开销。
即便如此,这种方案依然被我看做是最佳的实践方案,由于它比较简单。若是咱们追求“只实例化目标类”,那么可使用下面的方式声明内嵌类:
@Configuration @ComponentScan(value = "com.shouzheng.demo.web", useDefaultFilters = false, includeFilters = @ComponentScan.Filter( type = FilterType.REGEX, pattern = {"com.shouzheng.demo.web.CityService"}) ) static class InnerConfig { }
@ComponentScan
负责配置扫描Bean的方案,value属性指定扫描的根路径,useDefaultFilters属性取消默认的过滤器,includeFilters属性自定义了一个过滤器,这个过滤器设定为要扫描模式匹配的类。
@ComponentScan默认的过滤器会扫描@Component,@Repository,@Service,@Controller;若是不由用默认过滤器,自定义过滤器的效果是在默认过滤器的基础上追加更多的bean。即咱们要限定只实例化某个特定的bean,就须要把默认的过滤器禁用。
能够看到,这种扫描策略配置,会显得复杂不少。
@Autowired
负责注入依赖的bean,在这里注入的是测试目标bean。
@MockBean
负责声明这是一个模拟的bean。在进行单元测试时,须要将测试目标的全部依赖bean声明为模拟的bean,这些模拟的bean将被注入测试目标bean。
在testInsert方法中,咱们执行了cityMapper.insert
,这只是模拟的执行了,实际上什么也没作。接下来咱们调用Mockito.verify
,目的是验证cityMapper.insert
执行了。这正对应了上文中对Mock概念的解释,咱们只关心它是否执行了。
须要注意的是,验证的内容同时包括参数是否一致。若是实际调用时的传参和验证时指定的参数不一致,则验证失败,以致于测试失败。
在getAllCities方法中,咱们使用Mockito.when
对cityMapper.selectAllCities
方法进行打桩,设定当方法被调用时,直接返回咱们预设的数据。这也对应了上文中对Stub概念的解释。
注意:只能对mock对象进行stub。
Controller是一类特殊的bean,这类bean除了显式的依赖,还有一些系统组件的依赖。好比消息转换组件,负责将方法的返回结果转换成能够写的HTTP消息。因此,咱们没法像测试上文那样对其单独实例化。
Spring提供了特定的注解,配置用于测试Controller的上下文环境。
例如咱们要测试的controller以下:
@RestController public class CityController { @Autowired private CityService cityService; @GetMapping("/cities") public ResponseEntity<?> getAllCities() { List<City> cities = cityService.getAllCities(); return ResponseEntity.ok(cities); } @PostMapping("/city") public ResponseEntity<?> newCity(@RequestBody City city) { cityService.save(city); return ResponseEntity.ok(city); } }
咱们能够这样编写测试类:
@RunWith(SpringRunner.class) @WebMvcTest(CityController.class) public class CityControllerUnitTest { @Autowired private MockMvc mvc; @MockBean private CityService service; @Test public void getAllCities() throws Exception { City city = new City(); city.setId(1L); city.setName("杭州"); city.setState("浙江"); city.setCountry("中国"); Mockito.when(service.getAllCities()). thenReturn(Collections.singletonList(city)); mvc.perform(MockMvcRequestBuilders.get("/cities")) .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("杭州"))); } }
@WebMvcTest
是特定的注解,它的职责和@SpringBootTest
相同,但它只会实例化Controller。默认实例化全部的Controller,也能够指定只实例化某一到多个Controller。
除此以外,@WebMvcTest
还会实例化一个MockMvc的bean,用于发送http请求。
咱们一样须要对测试目标的依赖进行模拟,即,将CityService声明为MockBean。
spring环境问题
@WebMvcTest
就像@SpringBootTest
同样,默认搜索@SpringBootConfiguration
注解的类做为配置类。通常状况下,基于Spring-Boot的web应用,会建立一个启动类,并使用@SpringBootApplication
,这个注解可看做@SpringBootConfiguration
注解的扩展,因此极可能会搜索到这个启动类做为配置。
若是项目当中有多个@SpringBootConfiguration
配置类,好比有些其余的测试类建立了内部配置类,而且使用了这个注解。若是当前测试类没有使用内部类,也没有使用classes属性指定使用哪一个配置类,就会由于找到了多个配置类而失败。这种状况下会有明确的错误提示信息。
思考当前测试类会使用哪个配置类,是一个很好的习惯。
另一个可能的问题是:若是配置类上添加了其余的注解,好比Mybatis框架的@MapperScan
注解,那么Spring会去尝试实例化Mapper实例,可是由于咱们使用的是@WebMvcTest
注解,Spring不会去实例化Mapper所依赖的sqlSessionFactory等自动配置的组件,最终致使依赖注解失败,没法构建Spring上下文环境。
也就是说,虽然@WebMvcTest
默认只实例化Controller组件,可是它一样也会听从配置类的注解去作更多的工做。若是这些工做依赖于某些自动化配置bean,那么将会出现依赖缺失。
解决这个问题的方法可能有不少种,我这边提供一个本身的最佳实践:
@RunWith(SpringRunner.class) @WebMvcTest(CityController.class) public class CityControllerWebLayer { @SpringBootApplication(scanBasePackages = {"com.shouzheng.demo.web"}) static class InnerConfig {} @Autowired private MockMvc mvc; @MockBean private CityService service; }
这个方案,是经过使用内部类来自定义配置。内部类只有一个@SpringBootApplication
注解,指定了扫描的根路径,以缩小bean的扫描范围。
就像测试controller同样,持久层的单元测试也有专门的注解支持。
持久层的技术有多种,Spring提供了@JdbcTest
来支持经过spring的JdbcTemplate进行持久化的测试,提供了@DataJpsTest
支持经过JPA技术进行持久化的测试。
上面的这两个注解我没有作过研究,由于项目中使用的是Mybatis,这里仅介绍Mybatis提供的测试支持:@MybatisTest
。
最简单的方式是使用内存数据库做为测试数据库,这样能够尽可能减小测试的环境依赖。
默认的持久层测试是回滚的,即每个测试方法执行完成以后,会回滚对数据库的修改;因此也可使用外部的数据库进行测试,但多少会有些影响(好比序列的当前值)。
首先,添加数据库依赖:
<!-- pom.xml --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>RELEASE</version> <scope>test</scope> </dependency>
准备数据库初始化脚本,好比放在resources/import.sql文件中:
drop table if exists city; drop table if exists hotel; create table city (id int primary key AUTO_INCREMENT, name varchar, state varchar, country varchar); create table hotel (city int primary key AUTO_INCREMENT, name varchar, address varchar, zip varchar); insert into city (id, name, state, country) values (1, 'San Francisco', 'CA', 'US'); insert into hotel(city, name, address, zip) values (1, 'Conrad Treasury Place', 'William & George Streets', '4001')
须要在配置文件中指定脚本文件的位置:
spring.datasource.schema=classpath:import.sql
例如咱们要测试以下的Mapper接口:
@Mapper public interface CityMapper { City selectCityById(int id); List<City> selectAllCities(); int insert(City city); }
咱们能够这样编写测试类:
@RunWith(SpringRunner.class) @MybatisTest @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class CityMapperUnitTest { @SpringBootApplication(scanBasePackages = {"com.shouzheng.demo.mapper"}) static class InnerConfig {} private static Logger LOG = LoggerFactory.getLogger(CityMapperUnitTest.class); @Autowired private CityMapper cityMapper; @Before @After public void printAllCities() { List<City> cities = cityMapper.selectAllCities(); LOG.info("{}", cities); } @Test // @Rollback(false) // 禁止回滚 public void test1_insert() throws Exception { City city = new City(); city.setName("杭州"); city.setState("浙江"); city.setCountry("CN"); cityMapper.insert(city); LOG.info("insert a city {}", city); } @Test public void test2_doNothing() { } }
@MybatisTest
搜索配置类的逻辑和@SpringBootTest
、@WebMvcTest
相同,为了不Spring环境问题(上文在测试Controller一节中介绍过),这里直接使用内部类进行配置。
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
用来指定测试方法的执行顺序,这是为了观察事务回滚的效果。
若是将test1_insert方法上的@Rollback(false)
注释放开,事务不会回滚,test2_doNothing方法以后打印输出的内容会包含test1_insert方法里插入的数据。
反之,若是注释掉,事务回滚,test2_doNothing方法以后打印输出的内容不包含test1_insert方法里插入的数据。
首先,添加对应的数据库驱动依赖,以及数据源配置。好比使用mysql外部数据库:
<!-- pom.xml --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-jdbc.version}</version> </dependency>
# application.yml spring: datasource: url: jdbc:mysql://localhost:3306/test?autoReconnect=true&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&useSSL=false username: root password: root driver-class-name: com.mysql.jdbc.Driver
而后配置测试类,惟一不一样的是,在测试类上要多加一个@AutoConfigureTestDatabase
注解:
@RunWith(SpringRunner.class) @MybatisTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) public class CityMapperTest2 { @SpringBootApplication(scanBasePackages = {"com.shouzheng.demo.mapper"}) static class InnerConfig {} @Autowired private CityMapper cityMapper; // ... }
这样,测试的时候就会使用咱们配置的数据库进行测试,而不是使用内存数据库。
测试持久层时,默认是回滚的。能够在具体的测试方法上添加@Rollback(false)
来禁止回滚,也能够在测试类上添加。
集成测试时会超脱一个类的范围,咱们须要保证自测试目标类及如下的依赖类,都可以在spring容器中被实例化,最简单的方式莫过于构建完整的spring上下文。虽然这样一来,会有不少和测试目标无关的类也会被实例化,可是咱们省去了精心设计初始化bean的工夫,并且也间接的达到了“测试构建完整的spring上下文”的目的。
例如咱们以上文中介绍到的controller为测试目标,测试newCity请求。测试类以下:
@RunWith(SpringRunner.class) @SpringBootTest(classes = DemoTestSpringBootApplication.class) @AutoConfigureMockMvc @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class CityControllerWithRollbackTest { private static Logger LOG = LoggerFactory.getLogger(CityControllerWithRollbackTest.class); @Autowired private MockMvc mockMvc; @Before @After public void getAllCities() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/cities")) .andDo(result -> { String content = result.getResponse().getContentAsString(); LOG.info("cities = {}", content); }); } @Test @Transactional // @Rollback(false) public void test1_insertCity() throws Exception { LOG.info("insert a city"); mockMvc.perform(MockMvcRequestBuilders.post("/city") .contentType(MediaType.APPLICATION_JSON) .content("{\"name\": \"杭州\", \"state\": \"浙江\", \"country\": \"中国\"}")) .andExpect(MockMvcResultMatchers.status().isOk()); } /** * 为了观察数据库是否回滚 */ @Test public void test2_doNothind() { } }
这段代码主要测试新增数据记录的请求,并在测试先后分别请求并打印当前的数据记录集。咱们能够看到,在test1_insertCity方法运行以后打印的数据集,会比在此以前打印的数据集多一条记录,而这条记录正是咱们申请新增的数据记录。
test2_doNothind是一个辅助的测试方法,在完成test1_insertCity方法以后,开始执行test2_doNothind测试。而测试前的打印数据记录集的行为,可让咱们观察到test1_insertCity测试中新增的数据是否发生回滚。
集成测试时使用@SpringBootTest
注解,指定配置类为项目启动类。若是咱们的项目是基于spring-cloud的微服务环境,那么也可使用内部配置类来减小服务注册等相关的配置。
@AutoConfigureMockMvc
是为了实例化MockMvc实例,用来发送http请求。
实验证实,集成测试依然能够支持数据库操做回滚,方案就是在测试方法上使用@Transactional
注解,标识事务性操做。同时,咱们依然可使用@Rollback
来设置是否回滚。
集成测试不是非要从最顶层开始测试,咱们也能够从service层开始测试:
@RunWith(SpringRunner.class) @SpringBootTest(classes = {DemoTestSpringBootApplication.class}) @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class CityServiceWithRollbackTest { private static Logger LOG = LoggerFactory.getLogger(CityServiceWithRollbackTest.class); @Autowired private CityService cityService; @Before @After public void printAllCities() { List<City> cities = cityService.getAllCities(); LOG.info("{}", cities); } @Test @Transactional public void test1_insert() { City city = new City(); city.setName("杭州"); city.setState("浙江"); city.setCountry("CN"); cityService.save(city); LOG.info("insert a new city {}", city); } @Test public void test2_doNothind() { } }
这段代码的测试方案和上文的controller集成测试方案相同,都是测试新增操做,并在测试先后打印当前数据集,来演示是否支持事务回滚。
在spring项目的测试类中,咱们能够对任意的类进行mock,以下面这样:
@RunWith(SpringRunner.class) @SpringBootTest public class CityServiceUnitTest { @MockBean private CityMapper cityMapper; ... }
定义一个field,对其添加@MockBean
注解,就声明了对应类型的一个mock bean。若是spring上下文中已经存在对应类型的bean,将会被mock bean覆盖掉。
默认的状况下,mock bean的全部方法都是透明的:什么也不作,直接返回对应类型的默认值。声明返回引用类型的方法,将直接返回null;声明返回基本类型的方法,直接返回相应的默认值;声明无返回的方法,那更是透明的。
mock的做用对静态方法无效,静态方法会被实际调用。因此建议不要在静态方法中进行资源相关的处理,不然将没法进行模拟测试。好比,使用静态方法封装数据库操做的行为是很差的。
如上文所述,Mock的使用场景是咱们只关注对应的方法是否执行了,而不关心实际的执行效果。实际代码中,咱们能够按照下面的方式使用:
@Test @Transactional public void test1_insert() { City city = new City(); city.setName("杭州"); city.setState("浙江"); city.setCountry("CN"); cityService.save(city); Mockito.verify(cityMapper).insert(city); LOG.info("insert a new city {}", city); }
Mockito.verify
开始的一行,用来验证做为mock bean的cityMapper的insert方法会被执行,并且参数为city。若是方法没有被调用,或者实际调用时的传参不一致,都会致使测试失败。
好比,若是改为Mockito.verify(cityMapper).insert(new City());
,将会抛出下面的异常:
Argument(s) are different! Wanted: cityMapper bean.insert(null,null,null,null); -> at com.shouzheng.demo.web.CityServiceWithRollbackTest.test1_insert(CityServiceWithRollbackTest.java:56) Actual invocation has different arguments: cityMapper bean.insert(null,杭州,浙江,CN); -> at com.shouzheng.demo.web.CityService.save(CityService.java:26) Comparison Failure: Expected :cityMapper bean.insert(null,null,null,null); Actual :cityMapper bean.insert(null,杭州,浙江,CN);
在Mock的基础上更进一步,若是咱们关注方法的返回结果,或者咱们但愿方法能有预约的行为,使得测试按照咱们预期的方向进行,那么咱们须要对mock bean的某些方法进行stub,让这些方法在参数知足某个条件的状况下,给咱们预设的响应。
实际代码中,咱们只能对mock bean的方法进行stub,不然获得下面的异常:
org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles); Also, this error might show up because: 1. you stub either of: final/private/equals()/hashCode() methods. Those methods *cannot* be stubbed/verified. Mocking methods declared on non-public parent classes is not supported. 2. inside when() you don't call method on mock but on some other object.
咱们能够按照下面的方式,让它返回预设的结果:
Mockito.when(cityMapper.selectAllCities()) .thenReturn(Collections.singletonList(city));
或者抛出预设的异常(若是咱们检测异常处理代码的话):
Mockito.when(cityMapper.selectAllCities()) .thenThrow(new RuntimeException("test"));
或者去执行实际的方法:
when(mock.someMethod()).thenCallRealMethod();
注意,调用真实的方法有违mock的本义,应该尽可能避免。若是要调用的方法中调用了其余的依赖,须要自行注入其余的依赖,不然会空指针。
若是咱们但愿它可以执行预设的操做,好比打印咱们传入的参数,或者修改咱们传入的参数,咱们能够按照下面的方式实现:
Mockito.when(cityMapper.insert(Mockito.any())) .then(invocation -> { LOG.info("arguments are {}", invocation.getArguments()); return 1; });
咱们能够指定明确的参数匹配条件,或者使用模式匹配:
@RunWith(SpringRunner.class) @SpringBootTest public class MathServiceTest { @Configuration static class ConfigTest {} @MockBean private MathService mathService; @Test public void testDivide() { Mockito.when(mathService.divide(4, 2)) .thenReturn(2); Mockito.when(mathService.divide(8, 2)) .thenReturn(4); Mockito.when(mathService.divide(Mockito.anyInt(), Mockito.eq(0))) // 必须同时用模式 .thenThrow(new RuntimeException("error")); Assertions.assertThat(mathService.divide(4, 2)) .isEqualTo(2); Assertions.assertThat(mathService.divide(8, 2)) .isEqualTo(4); Assertions.assertThatExceptionOfType(RuntimeException.class) .isThrownBy(() -> { mathService.divide(3, 0); }) .withMessageContaining("error"); } }
上面的测试可能有些奇怪,mock的对象也同时做为测试的目标。这是由于咱们的目的在于介绍mock,因此简化了测试流程。
注意,若是咱们对方法的其中一个参数使用了模式,其余的参数都须要使用模式。好比下面这句:
Mockito.when(mathService.divide(Mockito.anyInt(), Mockito.eq(0)))
,咱们的本意是Mockito.when(mathService.divide(Mockito.anyInt(), 0))
,可是咱们不得不为第二个参数使用模式。
注解 | 说明 |
---|---|
@RunWith |
junit的注解,经过这个注解使用SpringRunner.class ,可以将junit和spring进行集成。后续的spring相关注解才会起效。 |
@SpringBootTest |
spring的注解,经过扫描应用程序中的配置来构建测试用的Spring上下文。 |
@AutoConfigureMockMvc |
spring的注解,可以自动配置MockMvc 对象实例,用来在模拟测试环境中发送http请求。 |
@WebMvcTest |
spring的注解,切片测试的一种。使之替换@SpringBootTest 能将构建bean的范围限定于web层,可是web层的下层依赖bean,须要经过mock来模拟。也能够经过参数指定只实例化web层的某一个到多个controller。具体可参考Auto-configured Spring MVC Tests。 |
@RestClientTest |
spring的注解,切片测试的一种。若是应用程序做为客户端访问其余Rest服务,能够经过这个注解来测试客户端的功能。具体参考Auto-configured REST Clients。 |
@MybatisTest |
mybatis按照spring的习惯开发的注解,切片测试的一种。使之替换@SpringBootTest ,可以将构建bean的返回限定于mybatis-mapper层。具体可参考mybatis-spring-boot-test-autoconfigure。 |
@JdbcTest |
spring的注解,切片测试的一种。若是应用程序中使用Jdbc做为持久层(spring的JdbcTemplate ),那么可使用该注解代替@SpringBootTest ,限定bean的构建范围。官方参考资料有限,可自行网上查找资料。 |
@DataJpaTest |
spring的注解,切片测试的一种。若是使用Jpa做为持久层技术,可使用这个注解,参考Auto-configured Data JPA Tests。 |
@DataRedisTest |
spring的注解,切片测试的一种。具体内容参考Auto-configured Data Redis Tests。 |