原标题:Spring、Spring Boot 和 TestNG 测试指南 ( 3 )

来源:chanjarster,

github.com/chanjarster/spring-test-examples

Spring&Spring Boot Testing工具提供了一些方便测试的Annotation,本文会对其中的一些做一些讲解。

@TestPropertySource

@TestPropertySource可以用来覆盖掉来自于系统环境变量,Java的系统属性,@PropertySource的属性。

同时@TestPropertySource(properties=…)优先级高于@TestPropertySource(locations=…)。

利用它我们可以很方便的在测试代码里微调,模拟配置(比如修改操作系统目录分隔符,数据源等)。

例子1:使用Spring Testing工具

我们先使用@PropertySource将一个外部属性文件加载进来,PropertySourceConfig:

@Configuration

@PropertySource(“ classpath:me / chanjar / annotation / testps / ex1 / property-source.properties ”)

public class PropertySourceConfig {

}

file: property-source.properties

foo=abc

然后我们用@TestPropertySource覆盖了这个特性:

TestPropertySource(properties = { “ foo = xyz ” ...

最后我们测试了是否覆盖成功(结果是成功的):

@Test

public void testOverridePropertySource(){

的assertEquals(环境。的getProperty( “ FOO ”), “ XYZ ”);

}

同时我们还对@TestPropertySource做了一些其他的测试,具体情况你可以自己观察。为了方便你观察@TestPropertySource对系统环境变量和Java的系统属性的覆盖效果,我们在一开始打印出了它们的值。

源代码TestPropertyTest:

@ContextConfiguration(类 = PropertySourceConfig 。类)

@TestPropertySource(

属性 = { “富= XYZ ”,“巴= UVW ”,“ PATH = AAA ”,“ java.runtime.name = BBB ” },

位置 = “类路径:我/chanjar/annotation/testps/ex1/test-property-source.properties “

)

公共 类 TestPropertyTest 扩展 AbstractTestNGSpringContextTests 实现 EnvironmentAware {

私人 环境环境;

@覆盖

公共 无效 setEnvironment(环境 环境){

此。环境=环境;

Map < String,Object > systemEnvironment =((ConfigurableEnvironment)环境)。getSystemEnvironment();

系统。出去。println(“ ===系统环境=== ”);

系统。出去。的println(getMapString(systemEnvironment));

系统。出去。的println();

系统。出去。println(“ === Java系统属性=== ”);

Map < String,Object > systemProperties =((ConfigurableEnvironment)环境)。getSystemProperties();

系统。出去。的println(getMapString(systemProperties));

}

@Test

public void testOverridePropertySource(){

的assertEquals(环境。的getProperty( “ FOO ”), “ XYZ ”);

}

@Test

public void testOverrideSystemEnvironment(){

的assertEquals(环境。的getProperty( “ PATH ”), “ AAA ”);

}

@Test

public void testOverrideJavaSystemProperties(){

的assertEquals(环境。的getProperty( “ java.runtime.name ”), “ BBB ”);

}

@Test

public void testInlineTestPropertyOverrideResourceLocationTestProperty(){

的assertEquals(环境。的getProperty( “条”), “ UVW ”);

}

private String getMapString(Map < String,Object > map){

return String 。加入(“ n ”,

地图。keySet()。stream()。地图(K - > ķ + “ = ” +地图。得到(k))的。收集(toList())

);

}

}

例子2:使用Spring Boot Testing工具

@TestPropertySource也可以和@SpringBootTest一起使用。

源代码见TestPropertyTest:

@SpringBootTest(类 = PropertySourceConfig 。类)

@TestPropertySource(

属性 = { “富= XYZ ”,“巴= UVW ”,“ PATH = AAA ”,“ java.runtime.name = BBB ” },

位置 = “类路径:我/chanjar/annotation/testps/ex1/test-property-source.properties “

)

公共 类 TestPropertyTest 扩展 AbstractTestNGSpringContextTests 实现 EnvironmentAware {

// ..

@ActiveProfiles

@ActiveProfiles可以用来在测试的时候启用某些资料的豆本章节的测试代码使用了下面的这个配置:

@Configuration

public class Config {

@Bean

@Profile(“ dev ”)

public Foo fooDev(){

return new Foo(“ dev ”);

}

@Bean

@Profile(“ product ”)

public Foo fooProduct(){

return new Foo(“ product ”);

}

@Bean

@Profile(“ default ”)

public Foo fooDefault(){

return new Foo(“ default ”);

}

@Bean

public bar bar(){

return new bar(“ no profile ”);

}

}

例子1:不使用ActiveProfiles

在没有@ActiveProfiles的时候,外形=默认和没有设定个人资料的豆会被加载到。

源代码ActiveProfileTest:

@ContextConfiguration(类 = 配置。类)

公共 类 ActiveProfileTest 延伸 AbstractTestNGSpringContextTests {

@Autowired

私人 Foo foo;

@Autowired

私人 酒吧 ;

@Test

public void test(){

的assertEquals(FOO 。的getName(), “默认”);

的assertEquals(巴。的getName(), “无简档”);

}

}

例子二:使用ActiveProfiles

当使用了@ActiveProfiles的时候,轮廓匹配的和没有设定个人资料的豆会被加载到。

源代码ActiveProfileTest:

@ContextConfiguration(类 = 配置。类)

[ @ActiveProfiles] [doc-active-profiles](“ product ”)

public class ActiveProfileTest extends AbstractTestNGSpringContextTests {

@Autowired

私人 Foo foo;

@Autowired

私人 酒吧 ;

@Test

public void test(){

的assertEquals(FOO 。的getName(), “产品”);

的assertEquals(巴。的getName(), “无简档”);

}

}

总结

在没有@ActiveProfiles的时候,外形=默认和没有设定个人资料的豆会被加载到。

当使用了@ActiveProfiles的时候,轮廓匹配的和没有设定个人资料的豆会被加载到。

@ActiveProfiles同样也可以和@SpringBootTest配合使用,这里就不举例说明了。

@JsonTest

@JsonTest是Spring Boot提供的方便测试JSON序列化反序列化的测试工具,在Spring Boot的文档中有一些介绍。

需要注意的是@JsonTest需要Jackson的ObjectMapper,事实上如果你的Spring Boot项目添加了spring-web的Maven依赖,JacksonAutoConfiguration就会自动为你配置一个:

org.springframework.boot

spring-boot-autoconfigure

org.springframework

spring-web

这里没有提供关于日期时间的例子,关于这个比较复杂,可以看我的另一篇文章:Spring Boot Jackson对于日期时间类型处理的例子。

https://github.com/chanjarster/springboot-jackson-datetime-example

例子1:简单例子

源代码见SimpleJsonTest:

@SpringBootTest(classes = SimpleJsonTest.class)

@JsonTest

public class SimpleJsonTest extends AbstractTestNGSpringContextTests {

@Autowired

private JacksonTester json;

@Test

public void testSerialize() throws Exception {

Foo details = new Foo("Honda", 12);

// 使用通包下的json文件测试结果是否正确

assertThat(this.json.write(details)).isEqualToJson("expected.json");

// 或者使用基于JSON path的校验

assertThat(this.json.write(details)).hasJsonPathStringValue("@.name");

assertThat(this.json.write(details)).extractingJsonPathStringValue("@.name").isEqualTo("Honda");

assertThat(this.json.write(details)).hasJsonPathNumberValue("@.age");

assertThat(this.json.write(details)).extractingJsonPathNumberValue("@.age").isEqualTo(12);

}

@Test

public void testDeserialize() throws Exception {

String content = "{"name":"Ford","age":13}";

Foo actual = this.json.parseObject(content);

assertThat(actual).isEqualTo(new Foo("Ford", 13));

assertThat(actual.getName()).isEqualTo("Ford");

assertThat(actual.getAge()).isEqualTo(13);

}

}

例子2: 测试@JsonComponent

@JsonTest可以用来测试@JsonComponent。

这个例子里使用了自定义的@JsonComponent FooJsonComponent:

@JsonComponent

public class FooJsonComponent {

public static class Serializer extends JsonSerializer {

@Override

public void serialize(Foo value, JsonGenerator gen, SerializerProvider serializers)

throws IOException, JsonProcessingException {

// ...

}

}

public static class Deserializer extends JsonDeserializer {

@Override

public Foo deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {

// ...

}

}

}

测试代码JsonComponentJsonTest:

@SpringBootTest(classes = { JsonComponentJacksonTest.class, FooJsonComponent.class })

@JsonTest

public class JsonComponentJacksonTest extends AbstractTestNGSpringContextTests {

@Autowired

private JacksonTester json;

@Test

public void testSerialize() throws Exception {

Foo details = new Foo("Honda", 12);

assertThat(this.json.write(details).getJson()).isEqualTo(""name=Honda,age=12"");

}

@Test

public void testDeserialize() throws Exception {

String content = ""name=Ford,age=13"";

Foo actual = this.json.parseObject(content);

assertThat(actual).isEqualTo(new Foo("Ford", 13));

assertThat(actual.getName()).isEqualTo("Ford");

assertThat(actual.getAge()).isEqualTo(13);

}

}

例子3: 使用@ContextConfiguration

事实上@JsonTest也可以配合@ContextConfiguration一起使用。

源代码见ThinJsonTest:

@JsonTest

@ContextConfiguration(classes = JsonTest.class)

public class ThinJsonTest extends AbstractTestNGSpringContextTests {

@Autowired

private JacksonTester json;

@Test

public void testSerialize() throws Exception {

// ...

}

@Test

public void testDeserialize() throws Exception {

// ...

}

}

@OverrideAutoConfiguration

在Spring、Spring Boot 和 TestNG 测试指南 ( 1 )提到:

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

那么当我们想在测试代码里关闭Auto Configuration如何处理?

方法1:提供另一套测试配置

方法2:使用@OverrideAutoConfiguration

方法1虽然能够很好的解决问题,但是比较麻烦。而方法2则能够不改变原有配置、不提供新的配置的情况下,就能够关闭Auto Configuration。

在本章节的例子里,我们自己做了一个Auto Configuration类,AutoConfigurationEnableLogger:

@Configuration

public class AutoConfigurationEnableLogger {

private static final Logger LOGGER = LoggerFactory.getLogger(AutoConfigurationEnableLogger.class);

public AutoConfigurationEnableLogger() {

LOGGER.info("Auto Configuration Enabled");

}

}

并且在META-INF/spring.factories里注册了它:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=

me.chanjar.annotation.overrideac.AutoConfigurationEnableLogger

这样一来,只要Spring Boot启动了Auto Configuration就会打印出日志:

2017-08-24 16:44:52.789 INFO 13212 --- [ main] m.c.a.o.AutoConfigurationEnableLogger : Auto Configuration Enabled

例子1:未关闭Auto Configuration

源代码见BootTest:

@SpringBootTest

@SpringBootApplication

public class BootTest extends AbstractTestNGSpringContextTests {

@Test

public void testName() throws Exception {

}

}

查看输出的日志,会发现Auto Configuration已经启用。

例子2:关闭Auto Configuration

然后我们用@OverrideAutoConfiguration关闭了Auto Configuration。

源代码见BootTest:

@SpringBootTest

@OverrideAutoConfiguration(enabled = false)

@SpringBootApplication

public class BootTest extends AbstractTestNGSpringContextTests {

@Test

public void testName() throws Exception {

}

}

再查看输出的日志,就会发现Auto Configuration已经关闭。

@TestConfiguration

@TestConfiguration是Spring Boot Test提供的一种工具,用它我们可以在一般的@Configuration之外补充测试专门用的Bean或者自定义的配置。

@TestConfiguration实际上是一种@TestComponent,@TestComponent是另一种@Component,在语义上用来指定某个Bean是专门用于测试的。

需要特别注意,你应该使用一切办法避免在生产代码中自动扫描到@TestComponent。 如果你使用@SpringBootApplication启动测试或者生产代码,@TestComponent会自动被排除掉,如果不是则需要像@SpringBootApplication一样添加TypeExcludeFilter:

//...

@ComponentScan(excludeFilters = {

@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),

// ...})

public @interface SpringBootApplication

例子1:作为内部类

@TestConfiguration和@Configuration不同,它不会阻止@SpringBootTest去查找机制(在Chapter 1: 基本用法 – 使用Spring Boot Testing工具 – 例子4提到过),正如@TestConfiguration的javadoc所说,它只是对既有配置的一个补充。

所以我们在测试代码上添加@SpringBootConfiguration,用@SpringBootTest(classes=…)或者在同package里添加@SpringBootConfiguration类都是可以的。

而且@TestConfiguration作为内部类的时候它是会被@SpringBootTest扫描掉的,这点和@Configuration一样。

测试代码TestConfigurationTest:

@SpringBootTest

@SpringBootConfiguration

public class TestConfigurationTest extends AbstractTestNGSpringContextTests {

@Autowired

private Foo foo;

@Test

assertEquals(foo.getName(), "from test config");

}

@TestConfiguration

public class TestConfig {

@Bean

public Foo foo() {

return new Foo("from test config");

}

}

}

例子2:对@Configuration的补充和覆盖

@TestConfiguration能够:

补充额外的Bean

覆盖已存在的Bean

要特别注意第二点,@TestConfiguration能够直接覆盖已存在的Bean,这一点正常的@Configuration是做不到的。

我们先提供了一个正常的@Configuration(Config):

@Configuration

public class Config {

@Bean

public Foo foo() {

return new Foo("from config");

}

}

又提供了一个@TestConfiguration,在里面覆盖了foo Bean,并且提供了foo2 Bean(TestConfig):

@TestConfiguration

public class TestConfig {

// 这里不需要@Primary之类的机制,直接就能够覆盖

@Bean

public Foo foo() {

return new Foo("from test config");

}

@Bean

public Foo foo2() {

return new Foo("from test config2");

}

}

测试代码TestConfigurationTest:

@SpringBootTest(classes = { Config.class, TestConfig.class })

public class TestConfigurationTest extends AbstractTestNGSpringContextTests {

@Qualifier("foo")

@Autowired

private Foo foo;

@Qualifier("foo2")

@Autowired

private Foo foo2;

@Test

assertEquals(foo.getName(), "from test config");

assertEquals(foo2.getName(), "from test config2");

}

}

再查看输出的日志,就会发现Auto Configuration已经关闭。

例子3:避免@TestConfiguration被扫描到

在上面的这个例子里的TestConfig是会被@ComponentScan扫描到的,如果要避免被扫描到,在本文开头已经提到过了。

先来看一下没有做任何过滤的情形,我们先提供了一个@SpringBootConfiguration(IncludeConfig):

@SpringBootConfiguration

@ComponentScan

public interface IncludeConfig {

}

然后有个测试代码引用了它(TestConfigIncludedTest):

@SpringBootTest(classes = IncludeConfig.class)

public class TestConfigIncludedTest extends AbstractTestNGSpringContextTests {

@Autowired(required = false)

private TestConfig testConfig;

@Test

assertNotNull(testConfig);

}

}

从这段代码可以看到TestConfig被加载了。

现在我们使用TypeExcludeFilter来过滤@TestConfiguration(ExcludeConfig1):

@SpringBootConfiguration

@ComponentScan(excludeFilters = {

@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)

})

public interface ExcludeConfig1 {

}

再来看看结果(TestConfigExclude_1_Test):

@SpringBootTest(classes = ExcludeConfig1.class)

public class TestConfigExclude_1_Test extends AbstractTestNGSpringContextTests {

@Autowired(required = false)

private TestConfig testConfig;

@Test

public void test() throws Exception {

assertNull(testConfig);

}

}

还可以用@SpringBootApplication来排除TestConfig(ExcludeConfig2):

@SpringBootApplication

public interface ExcludeConfig2 {

}

看看结果(TestConfigExclude_2_Test):

@SpringBootTest(classes = ExcludeConfig2.class)

public class TestConfigExclude_2_Test extends AbstractTestNGSpringContextTests {

@Autowired(required = false)

private TestConfig testConfig;

@Test

assertNull(testConfig);

}

}

参考文档

Spring框架测试

http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing

春季启动测试

http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing

具有测试属性源的上下文配置

https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/html/integration-testing.html#testcontext-ctx-management-property-sources

Spring Framework Testing

http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#testing

Spring Boot Testing

http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing

@JsonTest

http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-json-tests

JsonComponent

http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/jackson/JsonComponent.html

JacksonAutoConfiguration

http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.html

JacksonTester

http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/json/JacksonTester.html

GsonTester

http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/json/GsonTester.html

BasicJsonTester

http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/api/org/springframework/boot/test/json/BasicJsonTester.html

Detecting test configuration

https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-detecting-config

Excluding test configuration

https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-excluding-config

责任编辑:

boot spring test 文档_Spring、Spring Boot 和 TestNG 测试指南 ( 3 )相关推荐

  1. Spring Boot API 接口文档 Swagger 入门

    转载自 芋道 Spring Boot API 接口文档 Swagger 入门 摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/Swagger/ 「芋道源码」欢迎转 ...

  2. springboot实战pdf_Java程序员中秋节福利发送:Spring boot+Redis实战文档「PDF」

    中秋节越来越近了,平日里,各大公司拼员工拼技术拼实力:到了节日,则要拼奖金.拼福利.拼假期,还要拼创意.今天,小编为大家也准备了一份中秋节礼物,让我们一起来看看礼物是啥吧! Spring boot文档 ...

  3. Spring Boot 3.0.0-M1 Reference Documentation(Spring Boot中文参考文档) 9-16

    9. 数据 Spring Boot与多个数据技术集成,包括SQL和NoSQL. 9.1. SQL数据库 Spring Framework提供扩展支持用于与SQL数据工作,从使用JdbcTemplate ...

  4. oracle帮助文档_Spring Boot Config文档,使用IntelliJ IDEA的两种方法

    一个Spring Boot文档,两种方式. 在优锐课的java沙龙分享中,在现代软件开发中,应用程序由配置驱动. 如果可配置属性的数量很大,则很难记住每个属性的用途,结构或类型. 因此,有必要对这些属 ...

  5. Spring Security 文档

    Spring Security OAuth 已经不推荐使用了,最新的OAuth 2.0 的支持由Spring Security提供,官方给出了迁移指南 http://OAuth 2.0 Migrati ...

  6. GitHub标星75k,阿里15W字的Spring高级文档(全彩版),真的太香了

    随着 Spring 使用越来越广泛,Spring 已经成为 Java 程序员面试的必问知识点,很多同学对于Spring理解不是那么的深刻,经常就会被几个连环追问给干趴了! 今天小编整理了一下一线架构师 ...

  7. Spring帮助文档、API查看

    Spring帮助文档.API查看 这里的 spring指的是springFramework 一.打开网站首页 二.进入到springFramework介绍页面 三.点击LEARN查看文档内容

  8. Spring学习文档

    文章目录 Spring 创建maven项目,在项目中产生的pom.xml文件中,导入spring的坐标 Spring MVC Spring 创建maven项目,在项目中产生的pom.xml文件中,导入 ...

  9. spring boot api文档_Spring Boot: Spring Doc生成OpenAPI3.0文档

    1. 概述 公司正好最近在整理项目的文档,且文档对于构建REST API来说是至关重要的.在这篇文章中,我将介绍Spring Doc , 一个基于OpenAPI 3规范简化了Spring Boot 1 ...

最新文章

  1. sgdisk 磁盘操作命令
  2. 力扣: 88. 合并两个有序数组
  3. leetcode -- 357. Count Numbers with Unique Digits
  4. windows下面的txt在linux下面显示为乱码
  5. vector的求和用法accumulate
  6. “无法找到Internet Explorer”的解决方法
  7. 在网上找来的几个大牛,忽然觉得自己来参加ACM倒也不是一件错误的事情,梦想总是要有的,万一成了呢。
  8. java学习笔记14-多态
  9. 蓝桥杯历年省赛真题汇总及题目详解
  10. W10虚拟机一开机电脑蓝屏重启
  11. Testlink开启图片上传功能
  12. draco压缩引擎学习笔记(二)
  13. 软件测试b s环境如何配置,B/S架构测试环境搭建_SQLServer篇(Win32系统)
  14. Mybatis学习笔记-配置Log4j以便查看MyBatis操作数据库的过程
  15. antd 动态自定义表单验证失效
  16. 新办林业规划资质(丙级)应具备的条件?
  17. 今天去google中国采访从google总部回来的工程师(多图)
  18. idea 重新安装流程
  19. 阿里云BaaS下蚂蚁区块链开发实践(一)
  20. hadoop主要学什么?hadoop学习总结

热门文章

  1. 关于布地奈德的副作用
  2. Angular框架里两个模块的互相依赖
  3. CBA Opportunity Fiori应用的getEntitySet实现
  4. GM9 tile empty issue - ( not figured out )
  5. Fiori as a Service - FaaS - Creation of inline task option is not available
  6. doorway path issue of my task in HCP
  7. 蒙牛 customer Project Support - 同时更新两个database table
  8. One order error message log and storage
  9. utf8 and unicode
  10. Mockito框架研究 - how is match any string implemented