Github地址

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

Config:

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

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 = 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的文档:

  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:

@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。

Config:

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

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

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,它有这么几个好处:

  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:

@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:

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

  2. 提供nested @Configuration class

最佳实践

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

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

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

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

参考文档

            </div>

原文地址:https://segmentfault.com/a/1190000010854538

Spring、Spring Boot和TestNG测试指南 - 使用Spring Boot Testing工具的更多相关文章

  1. Spring Boot 2.0 升级指南

    Spring Boot 2.0 升级指南 前言 Spring Boot已经发布2.0有5个月多,多了很多新特性,一些坑也慢慢被填上,最近有空,就把项目中Spring Boot 版本做了升级,顺便整理下 ...

  2. Spring源码剖析开篇:什么是Spring?

    在讲源码之前,先让我们回顾一下一下Spring的基本概念,当然,在看源码之前你需要使用过spring或者spirngmvc. Spring是什么 Spring是一个开源的轻量级Java SE(Java ...

  3. spring boot项目如何测试,如何部署

    有很多网友会时不时的问我,spring boot项目如何测试,如何部署,在生产中有什么好的部署方案吗?这篇文章就来介绍一下spring boot 如何开发.调试.打包到最后的投产上线. 开发阶段 单元 ...

  4. Spring Boot 1.4测试的改进

    对Pivotal团队来说,工作上的好事情是他们拥有一个被叫做Pivotal Labs的灵活发展部门,拥有Labs团队的Lean 和 XP程序设计方法学的强大支持,例如结对编程和测试驱动开发.他们对于测 ...

  5. Spring Boot 1.4测试的简单理解

    首先maven要引入spring-boot-starter-test这个包. 先看一段代码 @RunWith(SpringRunner.class) @SpringBootTest(webEnviro ...

  6. 【星云测试】开发者测试-采用精准测试工具对Spring Boot应用进行测试

    简介:本文主要介绍把现今主流的springboot框架项目和精准测试工具进行结合和应用,通过精准测试的数据穿透.数据采集.测试用例与代码的双向追溯.数据分析等一系列精准测试的特有功能,达到对项目质量的 ...

  7. Spring Boot应用的测试——Mockito

    Spring Boot应用的测试——Mockito Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试:生成测试数据初始化数据库用于测试:Spring ...

  8. Spring Boot中的测试

    文章目录 简介 添加maven依赖 Repository测试 Service测试 测试Controller @SpringBootTest的集成测试 Spring Boot中的测试 简介 本篇文章我们 ...

  9. 曹工说Spring Boot源码(25)-- Spring注解扫描的瑞士军刀,ASM + Java Instrumentation,顺便提提Jar包破解

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

随机推荐

  1. poj2449第K短路问题(A*算法)

    启发函数:f(x)=g(x)+h(x); g(x)表示初始点到x状态的代价,h(x)表示从x的状态到目标状态的代价的估计值(并不是真实的),实际最小代价<=h(x); 起点s,终点t,x.v=s ...

  2. 【JZOJ4824】【NOIP2016提高A组集训第1场10.29】配对游戏

    题目描述 流行的跳棋游戏是在一个有m*n个方格的长方形棋盘上玩的.棋盘起初全部被动物或障碍物占满了.在一个方格中,'X'表示一个障碍物,一个'0'-'9'的个位数字表示一个不同种类的动物,相同的个位数 ...

  3. MyEclipse代码提示功能和自动提示功能

    1.菜单window->Preferences->Java->Editor->Content Assist->Enable auto activation 选项要打上勾 ...

  4. javaScript之split与join的区别

    共同点: split与join函数通常都是对字符或字符串的操作: 两者的区别: split() 用于分割字符串,返回一个数组,例如 var str="How are you doing to ...

  5. Java转iOS-第一个项目总结(2):遇到问题和解决方案

    目录1.UITableView滑动卡顿的优化 2.右滑手势返回 3.添加页面统计 4.debug版和release版 5.关于页面刷新 6.关于页面布局 7.推荐博客 遇到问题和解决方案 本文是Jav ...

  6. Java练习 SDUT-2053_整理音乐

    整理音乐 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 请用链表完成下面题目要求. xiaobai 很喜欢音乐,几年来 ...

  7. 使用DataWorks调度DLA循环任务

    DataWorks是阿里云上的一款热门产品,可以为用户提供大数据开发调度服务.它支持了Data Lake Analytics(后文简称DLA)以后,DLA用户可以通过它进行定时任务调度,非常方便.本文 ...

  8. @loj - 2507@ 「CEOI2011」Matching

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 对于整数序列 \((a_1, a_2, ..., a_n)\) ...

  9. shell学习(20)- xargs

    xargs 是给命令传递参数的一个过滤器,也是组合多个命令的一个工具. xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据. xargs 也可以将单行或多 ...

  10. ADT上跑java application

    Invalid layout of java.lang.String at value## A fatal error has been detected by the Java Runtime En ...