http://www.infoq.com/cn/articles/Unit-Testing-Complete-Integration-Testing-Begins

https://segmentfault.com/a/1190000010854538

前面一个部分讲解了如何使用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

@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(), 1);
} }

例子2:使用内嵌@Configuration加载Bean

源代码见FooServiceImpltest

@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(), 1);
} @Configuration
@Import(FooServiceImpl.class)
static class Config {
} }

例子3:使用外部@Configuration加载Bean

Config

@Configuration
@Import(FooServiceImpl.class)
public class Config {
}

FooServiceImpltest

@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(), 1);
} }

这个例子和例子2差不多,只不过将@Configuration放到了外部。

例子4:使用@SpringBootConfiguration

前面的例子@SpringBootTest的用法和@ContextConfiguration差不多。不过根据@SpringBootTest文档

  1. 它会尝试加载@SpringBootTest(classes=...)的定义的Annotated classes。Annotated classes的定义在ContextConfiguration中有说明。

  2. 如果没有设定@SpringBootTest(classes=...),那么会去找当前测试类的nested @Configuration class

  3. 如果上一步找到,则会尝试查找@SpringBootConfiguration,查找的路径有:1)看当前测试类是否@SpringBootConfiguration,2)在当前测试类所在的package里找。

所以我们可以利用这个特性来进一步简化测试代码。

Config

@SpringBootConfiguration
@Import(FooServiceImpl.class)
public class Config {
}

FooServiceImpltest

@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(), 1);
} }

例子5:使用@ComponentScan扫描Bean

前面的例子我们都使用@Import来加载Bean,虽然这中方法很精确,但是在大型项目中很麻烦。

在常规的Spring Boot项目中,一般都是依靠自动扫描机制来加载Bean的,所以我们希望我们的测试代码也能够利用自动扫描机制来加载Bean。

Config

@SpringBootConfiguration
@ComponentScan(basePackages = "me.chanjar.basic.service")
public class Config {
}

FooServiceImpltest

@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(), 1);
} }

例子6:使用@SpringBootApplication

也可以在测试代码上使用@SpringBootApplication,它有这么几个好处:

  1. 自身SpringBootConfiguration

  2. 提供了@ComponentScan配置,以及默认的excludeFilter,有了这些filter Spring在初始化ApplicationContext的时候会排除掉某些Bean和@Configuration

  3. 启用了EnableAutoConfiguration,这个特性能够利用Spring Boot来自动化配置所需要的外部资源,比如数据库、JMS什么的,这在集成测试的时候非常有用。

Config

@SpringBootApplication(scanBasePackages = "me.chanjar.basic.service")
public class Config {
}

FooServiceImpltest

@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(), 1);
} }

避免@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 Config1 {
} @SpringBootApplication(scanBasePackages = "me.chanjar.basic.service")
public class Config2 {
} @SpringBootTest
public class FooServiceImplTest extends AbstractTestNGSpringContextTests {
// ...
}

解决这个问题的方法有就是避免自动查询@SpringBootConfiguration

  1. 定义@SpringBootTest(classes=...)

  2. 提供nested @Configuration class

最佳实践

除了单元测试(不需要初始化ApplicationContext的测试)外,尽量将测试配置和生产配置保持一致。比如如果生产配置里启用了AutoConfiguration,那么测试配置也应该启用。因为只有这样才能够在测试环境下发现生产环境的问题,也避免出现一些因为配置不同导致的奇怪问题。

在测试代码之间尽量做到配置共用,这么做的优点有3个:

  1. 能够有效利用Spring TestContext Framework的缓存机制,ApplicationContext只会创建一次,后面的测试会直接用已创建的那个,加快测试代码运行速度。

  2. 当项目中的Bean很多的时候,这么做能够降低测试代码复杂度,想想如果每个测试代码都有一套自己的@Configuration或其变体,那得多吓人。

参考文档

例子7:

使用

@ContextHierarchy({
@ContextConfiguration(classes = {ServiceTestConfig.class}, loader = AnnotationConfigContextLoader.class)
})
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  loader=AnnotationConfigContextLoader.class,
  classes=ApplicationContextTestResourceNameType.class)
public class FieldResourceInjectionTest {
 
    @Resource(name="namedFile")
    private File defaultFile;
 
    @Test
    public void givenResourceAnnotation_WhenOnField_ThenDependencyValid(){
        assertNotNull(defaultFile);
        assertEquals("namedFile.txt", defaultFile.getName());
    }
}
@Configuration
public class ApplicationContextTestResourceNameType {
 
    @Bean(name="namedFile")
    public File namedFile() {
        File namedFile = new File("namedFile.txt");
        return namedFile;
    }
}
 
参考 
http://www.baeldung.com/spring-annotations-resource-inject-autowire

Springboot UT 引入某些类的更多相关文章

  1. Thinkphp 零散知识点(caa/js路径,引入第三方类,ajax返回,session/cookie)

    一.关于JS和CSS路径问题 1.找路径是从入口文件index.php来找的,而不是从文件本身所在位置来找, 因为我们访问时是访问的入口文件 2.在存放JS和CSS的时候可以放到public文件夹下 ...

  2. 尚硅谷springboot学习5-主入口类说明

    package com.atguigu; import org.springframework.boot.SpringApplication; import org.springframework.b ...

  3. SpringBoot启动加载类ApplicationRunner

    SpringBoot启动加载类ApplicationRunner 有时希望项目在启动的时候加载一些系统参数,就要用到ApplicationRunner ApplicationRunner是一个接口,我 ...

  4. springboot服务引入外部jar包在windows运行正常,在linux环境上无法加载到引入jar包的类

    一.问题描述 最近开发了一个springboot程序,需要依赖第三方jar包,这个jar包无法直接通过pom远程仓库下载,需要从自己本地引入,于是配置pom文件如下:将本地jar包引入工程,syste ...

  5. springboot中引入zookeeper,生成 配置类

    1.application.properties zookeeper.address=@mvn.zookeeper.address@ zookeeper.namespace=@mvn.zookeepe ...

  6. SSM项目 以及 springboot 中引入swagger2的方法

    swagger2是一个非常好用的接口文档,在开发的过程中方便前后端接口的交接. 下面我们就来讲讲在使用java时,分别在SSM框架,以及springboot+mybatis框架中引入swagger2的 ...

  7. SpringBoot入门02-配置类

    引入 Spring Boot的底层已经有了Spring MVC Spring Boot习惯优先的思想,很多配置都是可省的 不需要配置web.xml文件 不需要服务层的xml配置 不需要dao层的xml ...

  8. SpringBoot内置工具类,告别瞎写工具类了

    不知大家有没有注意到,接手的项目中存在多个重复的工具类,发现其中很多功能,Spring 自带的都有.于是整理了本文,希望能够帮助到大家! 一.断言 断言是一个逻辑判断,用于检查不应该发生的情况 Ass ...

  9. 引入DecimalFormat类进行数字格式化操作

    引入语句:import java.text.DecimalFormat; 首先创建DecimalFormat类对象,利用类对象调用Format()方法进行格式化操作.这里有两种方法:①.Decimal ...

随机推荐

  1. Delphi 调用SQL Server 2008存储过程

    1.表结构如下(预算数据明细表): CREATE TABLE [dbo].[BA_FeeDetail]( [ID] [int] IDENTITY(1,1) NOT NULL, [FeeDeptID] ...

  2. PL/SQL的下载与安装

    注意,为了更好的通用性,最好安装32位的. 下载地址为:https://www.allroundautomations.com/bodyplsqldevreg.html 当前最新正式版本为PL/SQL ...

  3. 开篇-QT完全手册

    嵌入式工具Qt的安装与使用 摘要 Qt是Trolltech公司的一个产品.Trolltech是挪威的一家软件公司,主要开 发两种产品:一种是跨平台应用程序界面框架:另外一种就是提供给做嵌入式Linux ...

  4. 读书笔记之:C语言深度剖析

    读书笔记之:C语言深度剖析 <C 语言深度解剖>这本书是一本“解开程序员面试笔试的秘密”的好书.作者陈正冲老师提出“以含金量勇敢挑战国内外同类书籍”,确实,这本书中的知识点都是一些在面试中 ...

  5. 如何解决Maven速度慢

    注:oschina已失效 Maven 远程仓库 <mirror> <id>ui</id> <mirrorOf>central</mirrorOf& ...

  6. 【BZOJ】【2527】【POI2011】Meteors

    整体二分+树状数组 整体二分……感谢zyf提供的入门题 简单粗暴的做法:枚举每一个国家,二分他的$w_i$,然后计算……然而这样效率很低…… 整体二分就是:对所有的国家一起进行二分,$w_i$在mid ...

  7. Android -- SharedPreferences存储信息

    背景                                                                                             Share ...

  8. Back Track 5 之 网络踩点(二)

    操作系统探测 Xprobe2 通过ICMP协议来获得指纹,通过模糊矩阵统计分析主动探测数据包对应的ICMP数据特征,进而探测得到远端操作系统的类型. 格式: ./xprobe2 域名 ./xprobe ...

  9. Spark+Kafka的Direct方式将偏移量发送到Zookeeper实现(转)

    原文链接:Spark+Kafka的Direct方式将偏移量发送到Zookeeper实现 Apache Spark 1.3.0引入了Direct API,利用Kafka的低层次API从Kafka集群中读 ...

  10. htmlDOM树

    原文: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM Shadow DOM API  研究一 ...