Spring、Spring Boot和TestNG测试指南 - 使用Spring Boot Testing工具
前面一个部分讲解了如何使用Spring Testing工具来测试Spring项目,现在我们讲解如何使用Spring Boot Testing工具来测试Spring Boot项目。
在Spring Boot项目里既可以使用Spring Boot Testing工具,也可以使用Spring Testing工具。
在Spring项目里,一般使用Spring Testing工具,虽然理论上也可以使用Spring Boot Testing,不过因为Spring Boot Testing工具会引入Spring Boot的一些特性比如AutoConfiguration,这可能会给你的测试带来一些奇怪的问题,所以一般不推荐这样做。
例子1:直接加载Bean
使用Spring Boot Testing工具只需要将@ContextConfiguration改成@SpringBootTest即可,源代码见FooServiceImpltest:
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), 1);
}
}" title="" data-original-title="复制">
@SpringBootTest(classes = FooServiceImpl.class)
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), <span class="hljs-number">1</span>);
}
}
例子2:使用内嵌@Configuration加载Bean
源代码见FooServiceImpltest:
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), 1);
}
@Configuration
@Import(FooServiceImpl.class)
static class Config {
}
}" title="" data-original-title="复制">
@SpringBootTest
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), <span class="hljs-number">1</span>);
}
@Configuration
@Import(FooServiceImpl.class)
static class Config {
}
}
例子3:使用外部@Configuration加载Bean
@Configuration
@Import(FooServiceImpl.class)
public class Config {
}
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), 1);
}
}" title="" data-original-title="复制">
@SpringBootTest(classes = Config.class)
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), <span class="hljs-number">1</span>);
}
}
这个例子和例子2差不多,只不过将@Configuration放到了外部。
例子4:使用@SpringBootConfiguration
前面的例子@SpringBootTest的用法和@ContextConfiguration差不多。不过根据@SpringBootTest的文档:
它会尝试加载
@SpringBootTest(classes=...)的定义的Annotated classes。Annotated classes的定义在ContextConfiguration中有说明。如果没有设定
@SpringBootTest(classes=...),那么会去找当前测试类的nested @Configuration class如果上一步找到,则会尝试查找
@SpringBootConfiguration,查找的路径有:1)看当前测试类是否@SpringBootConfiguration,2)在当前测试类所在的package里找。
所以我们可以利用这个特性来进一步简化测试代码。
@SpringBootConfiguration
@Import(FooServiceImpl.class)
public class Config {
}
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), 1);
}
}" title="" data-original-title="复制">
@SpringBootTest
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), <span class="hljs-number">1</span>);
}
}
例子5:使用@ComponentScan扫描Bean
前面的例子我们都使用@Import来加载Bean,虽然这中方法很精确,但是在大型项目中很麻烦。
在常规的Spring Boot项目中,一般都是依靠自动扫描机制来加载Bean的,所以我们希望我们的测试代码也能够利用自动扫描机制来加载Bean。
@SpringBootConfiguration
@ComponentScan(basePackages = "me.chanjar.basic.service")
public class Config {
}
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), 1);
}
}" title="" data-original-title="复制">
@SpringBootTest
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), <span class="hljs-number">1</span>);
}
}
例子6:使用@SpringBootApplication
也可以在测试代码上使用@SpringBootApplication,它有这么几个好处:
自身
SpringBootConfiguration提供了
@ComponentScan配置,以及默认的excludeFilter,有了这些filter Spring在初始化ApplicationContext的时候会排除掉某些Bean和@Configuration启用了
EnableAutoConfiguration,这个特性能够利用Spring Boot来自动化配置所需要的外部资源,比如数据库、JMS什么的,这在集成测试的时候非常有用。
@SpringBootApplication(scanBasePackages = "me.chanjar.basic.service")
public class Config {
}
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), 1);
}
}" title="" data-original-title="复制">
@SpringBootTest
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
@Autowired
private FooService foo;
@Test
public void testPlusCount() throws Exception {
assertEquals(foo.getCount(), 0);
foo.plusCount();
assertEquals(foo.getCount(), <span class="hljs-number">1</span>);
}
}
避免@SpringBootConfiguration冲突
当@SpringBootTest没有定义(classes=...,且没有找到nested @Configuration class的情况下,会尝试查询@SpringBootConfiguration,如果找到多个的话则会抛出异常:
Caused by: java.lang.IllegalStateException: Found multiple @SpringBootConfiguration annotated classes [Generic bean: class [...]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [/Users/qianjia/workspace-os/spring-test-examples/basic/target/test-classes/me/chanjar/basic/springboot/ex7/FooServiceImplTest1.class], Generic bean: class [me.chanjar.basic.springboot.ex7.FooServiceImplTest2]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [...]]
比如以下代码就会造成这个问题:
@SpringBootApplication(scanBasePackages = "me.chanjar.basic.service")
public class Config2 {
}
@SpringBootTest
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
// ...
}" title="" data-original-title="复制">
@SpringBootApplication(scanBasePackages = "me.chanjar.basic.service")
public class Config1 {
}
@SpringBootApplication(scanBasePackages = "me.chanjar.basic.service")
public class Config2 {
}
@SpringBootTest
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
// ...
}
解决这个问题的方法有就是避免自动查询@SpringBootConfiguration:
定义
@SpringBootTest(classes=...)提供nested @Configuration class
最佳实践
除了单元测试(不需要初始化ApplicationContext的测试)外,尽量将测试配置和生产配置保持一致。比如如果生产配置里启用了AutoConfiguration,那么测试配置也应该启用。因为只有这样才能够在测试环境下发现生产环境的问题,也避免出现一些因为配置不同导致的奇怪问题。
在测试代码之间尽量做到配置共用,这么做的优点有3个:
能够有效利用Spring TestContext Framework的缓存机制,ApplicationContext只会创建一次,后面的测试会直接用已创建的那个,加快测试代码运行速度。
当项目中的Bean很多的时候,这么做能够降低测试代码复杂度,想想如果每个测试代码都有一套自己的@Configuration或其变体,那得多吓人。
参考文档
</div>
Spring、Spring Boot和TestNG测试指南 - 使用Spring Boot Testing工具的更多相关文章
- Spring Boot 2.0 升级指南
Spring Boot 2.0 升级指南 前言 Spring Boot已经发布2.0有5个月多,多了很多新特性,一些坑也慢慢被填上,最近有空,就把项目中Spring Boot 版本做了升级,顺便整理下 ...
- Spring源码剖析开篇:什么是Spring?
在讲源码之前,先让我们回顾一下一下Spring的基本概念,当然,在看源码之前你需要使用过spring或者spirngmvc. Spring是什么 Spring是一个开源的轻量级Java SE(Java ...
- spring boot项目如何测试,如何部署
有很多网友会时不时的问我,spring boot项目如何测试,如何部署,在生产中有什么好的部署方案吗?这篇文章就来介绍一下spring boot 如何开发.调试.打包到最后的投产上线. 开发阶段 单元 ...
- Spring Boot 1.4测试的改进
对Pivotal团队来说,工作上的好事情是他们拥有一个被叫做Pivotal Labs的灵活发展部门,拥有Labs团队的Lean 和 XP程序设计方法学的强大支持,例如结对编程和测试驱动开发.他们对于测 ...
- Spring Boot 1.4测试的简单理解
首先maven要引入spring-boot-starter-test这个包. 先看一段代码 @RunWith(SpringRunner.class) @SpringBootTest(webEnviro ...
- 【星云测试】开发者测试-采用精准测试工具对Spring Boot应用进行测试
简介:本文主要介绍把现今主流的springboot框架项目和精准测试工具进行结合和应用,通过精准测试的数据穿透.数据采集.测试用例与代码的双向追溯.数据分析等一系列精准测试的特有功能,达到对项目质量的 ...
- Spring Boot应用的测试——Mockito
Spring Boot应用的测试——Mockito Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试:生成测试数据初始化数据库用于测试:Spring ...
- Spring Boot中的测试
文章目录 简介 添加maven依赖 Repository测试 Service测试 测试Controller @SpringBootTest的集成测试 Spring Boot中的测试 简介 本篇文章我们 ...
- 曹工说Spring Boot源码(25)-- Spring注解扫描的瑞士军刀,ASM + Java Instrumentation,顺便提提Jar包破解
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
随机推荐
- Java中的四种引用(强引用、软引用、弱引用、虚引用)
以下内容摘自<深入理解Java虚拟机 JVM高级特性与最佳实践>第2版,强烈推荐没有看过的同学阅读,读完的感觉就是"原来学的都是些什么瘠薄东西(╯‵□′)╯︵┴─┴" ...
- 利用 JavaScript SDK 部署网页版“Facebook 登录”
facebook开发者平台https://developers.facebook.com/ 利用 JavaScript SDK 部署网页版“Facebook 登录” 通过采用 Javascript 版 ...
- zabbix监控docker容器
1.环境说明 由于最近zabbix进行过一次迁移,所以zabbix-server系列采用docker方式安装,参考zabbix官网:https://github.com/zabbix/zabbix-d ...
- 小爬爬6.scrapy回顾和手动请求发送
1.数据结构回顾 #栈def push(self,item) def pop(self) #队列 def enqueue(self,item) def dequeue(self) #列表 def ad ...
- Java面向对象----多态概念,对象上下转型
概念:同一操作作用于某一类对象,可以有不同的解释,产生不同的执行结果 多态存在的三个必要条件 需要存在继承和实现关系 同样的 方法调用而执行不同操作,运行不同的代码(重写操作) 在运行时父类或者接口的 ...
- hdu 1003 hdu 1231 最大连续子序列【dp】
HDU1003 HDU1231 题意自明.可能是真的进步了点,记得刚开始研究这个问题时还想了好长时间,hdu 1231还手推了很长时间,今天重新写干净利落就AC了. #include<iostr ...
- Alpha版本第一周作业
姓名 学号 周前计划安排 每周实际工作记录 自我打分 LTR 61213 1.撰写博客2.分配具体任务并完成个人任务 1.已完成博客撰写2.任务分配完成并继续构思实现方法 95 LHL 61212 完 ...
- JPA中id前面有空格导致的"Column 'id' not found"问题
问题背景 昨晚有个同事发生了一个神奇的问题,一如既往的问题,一如既然的用我写的BEJSON-JAVA代码生成器生成,却发现一直提示Column 'id' not found.这就很TM神奇了 2018 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
- 因为对 Docker 不熟悉建了 N 多个 Nginx
因为对 Docker 不熟悉建了 N 多个 Nginx 一直不停的 docker run nginx 结果出现无数个 nginx. 然后最原来的 nginx 启动不了了. 使用 docker ps - ...