点击蓝色“程序猿DD”关注我哟

加个“星标”,不忘签到哦

转载自公众号:锅外的大佬


关注我,回复口令获取可获取独家整理的学习资料:

001:领取《Spring Boot基础教程》

002:领取《Spring Cloud基础教程》

- 003:领取《Java开发规范1.5》(最新版)

认认真真推荐9个值得关注的公众号

1、概览

众所周知,自动配置是Spring Boot的关键功能之一, 但测试自动配置可能会很棘手。

在以下部分中,我们将展示ApplicationContextRunner如何简化自动配置测试

2、测试自动化配置方案

ApplicationContextRunner是一个实用程序类,它运行ApplicationContext并提供AssertJ样式断言最好用作测试类中的字段以便共享配置,然后我们在每个测试中进行自定义:

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();

让我们通过测试一些案例来展示它的魔力。

2.1. 测试Class Condition

在本节中,我们将测试一些使用@ConditionalOnClass和@ConditionalOnMissingClass 注解的自动配置类:

@Configuration
@ConditionalOnClass(ConditionalOnClassIntegrationTest.class)
protected static class ConditionalOnClassConfiguration {    @Bean  public String created() {   return "This is created when ConditionalOnClassIntegrationTest is present on the classpath";  }
}   @Configuration
@ConditionalOnMissingClass("com.baeldung.autoconfiguration.ConditionalOnClassIntegrationTest")
protected static class ConditionalOnMissingClassConfiguration { @Bean  public String missed() {    return "This is missed when ConditionalOnClassIntegrationTest is present on the classpath";   }
}

我们想测试自动配置是否正确实例化或跳过createdmissing beans给定的预期条件。

  • ApplicationContextRunner为我们提供了withUserConfiguration方法,我们可以根据需要提供自动配置,以便为每个测试自定义ApplicationContext

  • run 方法将 ContextConsumer 作为将断言应用于上下文的参数。测试退出时,ApplicationContext将自动关闭:

@Test
public void whenDependentClassIsPresent_thenBeanCreated() { this.contextRunner.withUserConfiguration(ConditionalOnClassConfiguration.class) .run(context -> {    assertThat(context).hasBean("created");   assertThat(context.getBean("created"))    .isEqualTo("This is created when ConditionalOnClassIntegrationTest is present on the classpath"); });
}   @Test
public void whenDependentClassIsPresent_thenBeanMissing() { this.contextRunner.withUserConfiguration(ConditionalOnMissingClassConfiguration.class)  .run(context -> {    assertThat(context).doesNotHaveBean("missed");    });
}

通过前面的示例,我们发现测试classpath上存在某个类的场景的简单性。但是,当类不在classpath上时,我们如何测试相反的情况呢

这就是FilteredClassLoader发挥作用的地方。它用于在运行时过滤classpath上指定的类:

@Test
public void whenDependentClassIsNotPresent_thenBeanMissing() {  this.contextRunner.withUserConfiguration(ConditionalOnClassConfiguration.class) .withClassLoader(new FilteredClassLoader(ConditionalOnClassIntegrationTest.class))  .run((context) -> {  assertThat(context).doesNotHaveBean("created");   assertThat(context).doesNotHaveBean(ConditionalOnClassIntegrationTest.class);   });
}   @Test
public void whenDependentClassIsNotPresent_thenBeanCreated() {  this.contextRunner.withUserConfiguration(ConditionalOnMissingClassConfiguration.class)  .withClassLoader(new FilteredClassLoader(ConditionalOnClassIntegrationTest.class))  .run((context) -> {  assertThat(context).hasBean("missed");    assertThat(context).getBean("missed") .isEqualTo("This is missed when ConditionalOnClassIntegrationTest is present on the classpath");  assertThat(context).doesNotHaveBean(ConditionalOnClassIntegrationTest.class);   });
}

2.2. 测试 Bean Condition

我们刚刚测试了 @ConditionalOnClass 和@ConditionalOnMissingClass注解, 现在 让我们看看使用@ConditionalOnBean和@ConditionalOnMissingBean注释时的情况。

首先, 我们同样需要 一些自动配置的类:

@Configuration
protected static class BasicConfiguration { @Bean  public String created() {   return "This is always created";  }
}
@Configuration
@ConditionalOnBean(name = "created")
protected static class ConditionalOnBeanConfiguration { @Bean  public String createOnBean() {  return "This is created when bean (name=created) is present";    }
}
@Configuration
@ConditionalOnMissingBean(name = "created")
protected static class ConditionalOnMissingBeanConfiguration {  @Bean  public String createOnMissingBean() {   return "This is created when bean (name=created) is missing";    }
}

然后,我们将像上一节一样调用withUserConfiguration方法,然后发送我们的自定义配置类来测试自动配置是否在不同的条件下恰当地实例化bean或跳过createOnBeancreateOnMissingBean :

@Test
public void whenDependentBeanIsPresent_thenConditionalBeanCreated() {   this.contextRunner.withUserConfiguration(BasicConfiguration.class,  ConditionalOnBeanConfiguration.class)   // ommitted for brevity
}
@Test
public void whenDependentBeanIsNotPresent_thenConditionalMissingBeanCreated() { this.contextRunner.withUserConfiguration(ConditionalOnMissingBeanConfiguration.class)   // ommitted for brevity
}

2.3. 测试 Property Condition

在本节中,我们测试使用@ConditionalOnPropertyannotations的自动配置类。

首先,我们需要这个测试的属性:

com.baeldung.service=custom

然后,我们编写嵌套的自动配置类,根据前面的属性创建bean:

@Configuration
@TestPropertySource("classpath:ConditionalOnPropertyTest.properties")
protected static class SimpleServiceConfiguration { @Bean  @ConditionalOnProperty(name = "com.baeldung.service", havingValue = "default")   @ConditionalOnMissingBean  public DefaultService defaultService() {    return new DefaultService();    }   @Bean  @ConditionalOnProperty(name = "com.baeldung.service", havingValue = "custom")    @ConditionalOnMissingBean  public CustomService customService() {  return new CustomService(); }
}

现在,我们调用withPropertyValues方法来覆盖每个测试中的属性值:

@Test
public void whenGivenCustomPropertyValue_thenCustomServiceCreated() {   this.contextRunner.withPropertyValues("com.baeldung.service=custom") .withUserConfiguration(SimpleServiceConfiguration.class)    .run(context -> {    assertThat(context).hasBean("customService"); SimpleService simpleService = context.getBean(CustomService.class);    assertThat(simpleService.serve()).isEqualTo("Custom Service");    assertThat(context).doesNotHaveBean("defaultService");    });
}   @Test
public void whenGivenDefaultPropertyValue_thenDefaultServiceCreated() { this.contextRunner.withPropertyValues("com.baeldung.service=default")    .withUserConfiguration(SimpleServiceConfiguration.class)    .run(context -> {    assertThat(context).hasBean("defaultService");    SimpleService simpleService = context.getBean(DefaultService.class);   assertThat(simpleService.serve()).isEqualTo("Default Service");   assertThat(context).doesNotHaveBean("customService"); });
}

3、结论

总结一下, 这篇教程主要展示 如何使用ApplicationContextRunner运行带有自定义的ApplicationContext并应用断言.

我们在这里介绍了最常用的场景,而不是列出如何自定义ApplicationContext 。

在此期间,请记住ApplicationConetxtRunner适用于非Web应用程序,因此请考虑WebApplicationContextRunner用于基于servlet的Web应用程序,ReactiveWebApplicationContextRunner用于响应式Web应用程序。

本文源代码,请访问GitHub。

原文:https://www.baeldung.com/spring-boot-context-runner

作者:baeldung

译者:Leesen

推荐关注

推荐一个专注于国外大佬文章的翻译与发布的公众号。通过这个公众号,可以帮助我们紧跟技术的国际化发展趋势。


推荐阅读

  • 阿里云新版主页,我还以为打开了淘宝...

  • 19条效率至少提高3倍的MySQL技巧

  • 一次心惊肉跳的服务器误删文件的恢复过程

  • 阿里P10、腾讯T4、华为18都是怎样的神级收入?

  • Git 自救指南:这些坑你都跳得出吗?


自律到极致 - 人生才精致:第9期

正在筹备中!

关注我,加个星标,不忘签到哦~

2019

与大家聊聊技术人的斜杠生活

点一点“阅读原文”小惊喜在等你

Spring Boot ApplicationContextRunner 测试指南相关推荐

  1. Spring Boot 中文参考指南

    Spring Boot 版本 2.7.8 原文:https://docs.spring.io/spring-boot/docs/2.7.8/reference/htmlsingle/ - 笔者注: S ...

  2. SpringBoot入门系列: Spring Boot的测试

    Spring Boot的测试,和普通项目的测试类同,可以继续使用我们熟悉的测试工具.当然,这里的测试,主要还是后台代码的测试. 主要需要注意的地方仅有三点: 1.依赖包的引入:pom.xml中仅依赖s ...

  3. Spring Boot JUnit 测试 Controller

    Spring Boot JUnit 测试 Controller Controller层代码如下: @RestController public class HelloController {Logge ...

  4. idea启动springboot卡_写给新手看的 Spring Boot 入门学习指南

    什么是 Spring Boot ? 解释一下:Spring Boot 可以构建一切.Spring Boot 设计之初就是为了最少的配置,最快的速度来启动和运行 Spring 项目.Spring Boo ...

  5. Spring Boot 配置元数据指南

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 作者 | 遗失的拂晓 来源 | 公众号「锅外的大佬」 1. 概览 在编写 Spring Bo ...

  6. idea构建springboot项目右边没有maven_写给新手看的 Spring Boot 入门学习指南

    什么是 Spring Boot ? 解释一下:Spring Boot 可以构建一切.Spring Boot 设计之初就是为了最少的配置,最快的速度来启动和运行 Spring 项目.Spring Boo ...

  7. Spring boot(十二):Spring boot 如何测试、打包、部署

    博文引用:springboot(十二):springboot如何测试打包部署 开发阶段 单元测试 Spring boot对单元测试的支持已经很完善了. 1 在pom包中添加Spring-boot-st ...

  8. (转)Spring Boot(十二):Spring Boot 如何测试打包部署

    http://www.ityouknow.com/springboot/2017/05/09/spring-boot-deploy.html 有很多网友会时不时的问我, Spring Boot 项目如 ...

  9. 写给新手看的 Spring Boot 入门学习指南

    什么是 Spring Boot ? 解释一下:Spring Boot 可以构建一切.Spring Boot 设计之初就是为了最少的配置,最快的速度来启动和运行 Spring 项目.Spring Boo ...

最新文章

  1. 【Kubernetes】如何使用Kubeadm部署K8S集群
  2. msql每个数据前面添加某个字符串查询或者更新
  3. shell中获取单个文件大小
  4. 【Tools】cmake之编写CMakeLists.txt示例
  5. 《系统集成项目管理工程师》必背100个知识点-98大数据的特点
  6. Tomcat 怎么停止服务的?
  7. 【Java基础】List迭代并修改时出现的ConcurrentModificationException问题
  8. python 数字转化excel行列_Python实现excel的列名称转数字、26进制(A-Z)与10进制互相转换...
  9. FLEX常用验证控件
  10. 【原创】大叔问题定位分享(4)Kafka集群broker节点从zookeeper上消失
  11. java redis监听问题_springboot+redis过期事件监听实现过程解析
  12. 比char还小的变量
  13. PDF文件批量添加目录详细教程
  14. 【转载】原生Ajax写法
  15. 24年未遇之奇景再等等 Intel旗舰显卡曝5-6月发布
  16. 免费软电话 — X-Lite 的安装及配置向导
  17. 2022百度网盘目录管理系统
  18. 【性能监控】TTI (Time to interactive)
  19. android官网m魅族15,还是熟悉的味道,魅族三款15系新机现身安卓官网
  20. MQTT(一)C#使用 MQTTnet 快速实现 MQTT 通信(文末有完整Demo下载)

热门文章

  1. java 反序列化 ysoserial exploit/JRMPClient 原理剖析
  2. linux libuv 交叉编译 高性能事件驱动库
  3. java jar 和 war 包的区别
  4. python 根据时间来生成唯一的字符串
  5. 数组中存储不定个数的元素
  6. Linux System Programming --Chapter Seven
  7. python中构造方法可以被继承吗_构造函数是在python中继承的吗
  8. CMakeFile命令之file
  9. java日历表打印_Java打印日历表
  10. 初中学历怎么学计算机管理,初中学历能否学习计算机