测试Spring Boot有条件的合理方式

如果您或多或少有经验的Spring Boot用户,那么很幸运,在某些时候您可能需要遇到必须有条件地注入特定bean或配置的情况 。 它的机制是很好理解的 ,但有时这样的测试条件下(以及它们的组合)可能会导致混乱。 在这篇文章中,我们将讨论一些可行的方法(可以说是理智的)。

由于Spring Boot 1.5.x仍被广泛使用(不过,它将在8月向EOL迈进),因此我们会将其与Spring Boot 2.1.x一起包括在JUnit 4.x和JUnit 5.x中 。 我们将要介绍的技术同样适用于常规配置类和自动配置类。

我们将使用的示例与我们的自制日志记录有关。 让我们假设我们的Spring Boot应用程序需要一些名称为“ sample”的专用记录器bean。 但是,在某些情况下,必须禁用此记录器(或实际上使其成为noop),因此在这里,属性logging.enabled就像一个kill开关。 在此示例中,我们使用Slf4j和Logback ,但这并不是很重要。 下面的LoggingConfiguration片段反映了这个想法。

 @Configuration  public class LoggingConfiguration { @Configuration @ConditionalOnProperty (name = "logging.enabled" , matchIfMissing = true ) public static class Slf4jConfiguration { @Bean Logger logger() { return LoggerFactory.getLogger( "sample" ); } }     @Bean @ConditionalOnMissingBean Logger logger() { return new NOPLoggerFactory().getLogger( "sample" ); }  } 

那么我们将如何测试呢? Spring Boot (通常是Spring Framework )一直提供出色的测试脚手架支持 。 @SpringBootTest@TestPropertySource批注允许使用自定义属性快速引导应用程序上下文。 但是,有一个问题:它们是按测试类级别而不是每种测试方法应用的。 这当然是有道理的,但基本上需要您为每个条件组合创建一个测试类。

如果您仍然使用JUnit 4.x ,则可能会发现一个有用的技巧,该技巧利用了封闭的运行器(封闭的框架)。

 @RunWith (Enclosed. class (Enclosed. )  public class LoggingConfigurationTest { @RunWith (SpringRunner. class ) @SpringBootTest public static class LoggerEnabledTest { @Autowired private Logger logger;         @Test public void loggerShouldBeSlf4j() { assertThat(logger).isInstanceOf(ch.qos.logback.classic.Logger. class ); } }     @RunWith (SpringRunner. class ) @SpringBootTest @TestPropertySource (properties = "logging.enabled=false" ) public static class LoggerDisabledTest { @Autowired private Logger logger;         @Test public void loggerShouldBeNoop() { assertThat(logger).isSameAs(NOPLogger.NOP_LOGGER); } }  } 

您仍然可以按条件获得类,但至少它们都在同一嵌套中。 使用JUnit 5.x ,有些事情变得容易了,但没有达到人们期望的水平。 不幸的是, Spring Boot 1.5.x本身并不支持JUnit 5.x ,因此我们必须依靠spring-test-junit5社区模块提供的扩展。 这是pom.xml中的相关更改,请注意, spring-boot-starter-test依赖关系图中明确排除了junit

 < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-test</ artifactId > < scope >test</ scope > < exclusions > < exclusion > < groupId >junit</ groupId > < artifactId >junit</ artifactId > </ exclusion > </ exclusions >  </ dependency >  < dependency > < groupId >com.github.sbrannen</ groupId > < artifactId >spring-test-junit5</ artifactId > < version >1.5.0</ version > < scope >test</ scope >  </ dependency >  < dependency > < groupId >org.junit.jupiter</ groupId > < artifactId >junit-jupiter-api</ artifactId > < version >5.5.0</ version > < scope >test</ scope >  </ dependency >  < dependency > < groupId >org.junit.jupiter</ groupId > < artifactId >junit-jupiter-engine</ artifactId > < version >5.5.0</ version > < scope >test</ scope >  </ dependency > 

除了使用@Nested批注(来自JUnit 5.x以支持将测试作为内部类)之外,测试用例本身没有太大区别。

 public class LoggingConfigurationTest { @Nested @ExtendWith (SpringExtension. class ) @SpringBootTest @DisplayName ( "Logging is enabled, expecting Slf4j logger" ) public static class LoggerEnabledTest { @Autowired private Logger logger;         @Test public void loggerShouldBeSlf4j() { assertThat(logger).isInstanceOf(ch.qos.logback.classic.Logger. class ); } }     @Nested @ExtendWith (SpringExtension. class ) @SpringBootTest @TestPropertySource (properties = "logging.enabled=false" ) @DisplayName ( "Logging is disabled, expecting NOOP logger" ) public static class LoggerDisabledTest { @Autowired private Logger logger;         @Test public void loggerShouldBeNoop() { assertThat(logger).isSameAs(NOPLogger.NOP_LOGGER); } }  } 

如果尝试使用Apache Maven和Maven Surefire插件从命令行运行测试,则可能会惊讶地发现在构建过程中没有执行任何测试。 问题是… 排除了所有嵌套类 …因此我们需要采用另一种解决方法 。

 < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-surefire-plugin</ artifactId > < version >2.22.2</ version > < configuration > < excludes > < exclude /> </ excludes > </ configuration >  </ plugin > 

这样,事情应该顺利进行。 但是关于传统的足够多的是, Spring Boot 2.1.x作为完整的游戏改变者来了。 上下文运行程序家族ApplicationContextRunnerReactiveWebApplicationContextRunnerWebApplicationContextRunner提供了一种简单明了的方法,可以在每个测试方法级别上定制上下文,从而使测试执行异常Swift。

 public class LoggingConfigurationTest { private final ApplicationContextRunner runner = new ApplicationContextRunner() .withConfiguration(UserConfigurations.of(LoggingConfiguration. class ));     @Test public void loggerShouldBeSlf4j() { runner .run(ctx -> assertThat(ctx.getBean(Logger. class )).isInstanceOf(Logger. class ) ); }     @Test public void loggerShouldBeNoop() { runner .withPropertyValues( "logging.enabled=false" ) .run(ctx -> assertThat(ctx.getBean(Logger. class )).isSameAs(NOPLogger.NOP_LOGGER) ); }  } 

看起来真的很棒。 Spring Boot 2.1.x对JUnit 5.x的支持要好得多,并且在即将到来的2.2版本中 发布时, JUnit 5.x将是默认引擎 (不用担心,仍将支持旧的JUnit 4.x )。 到目前为止,切换到JUnit 5.x需要在依赖项方面进行一些工作。

 < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-test</ artifactId > < scope >test</ scope > < exclusions > < exclusion > < groupId >junit</ groupId > < artifactId >junit</ artifactId > </ exclusion > </ exclusions >  </ dependency >  < dependency > < groupId >org.junit.jupiter</ groupId > < artifactId >junit-jupiter-api</ artifactId > < scope >test</ scope >  </ dependency >  < dependency > < groupId >org.junit.jupiter</ groupId > < artifactId >junit-jupiter-engine</ artifactId > < scope >test</ scope >  </ dependency > 

作为附加步骤,您可能需要使用最新的Maven Surefire插件 ( 2.22.0或更高版本)以及现成的JUnit 5.x支持。 下面的代码段说明了这一点。

 < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-surefire-plugin</ artifactId > < version >2.22.2</ version >  </ plugin > 

我们使用的示例配置非常幼稚,许多实际应用程序最终将具有由许多条件构建而成的非常复杂的上下文。 上下文赛跑者带来的灵活性和巨大的机会, Spring Boot 2.x测试脚手架的宝贵补充,只是节省大量资金,请紧记它们。

完整的项目资源可在Github上找到 。

翻译自: https://www.javacodegeeks.com/2019/08/testing-spring-boot-conditionals-sane-way.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/341224.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

金山打字通答案

背景 金山打字通练习键盘键位&#xff0c;需要对第一关熟悉键盘知识进行答题。一下整理答案 答案 ABADCBCA

Onetab快速删除所有历史网页

1. 打开网页的控制台&#xff08;F12&#xff09; 2. 控制台粘贴该命令 document.querySelectorAll(div.deleteAllButton).forEach(function(ele, index, list){ele.click();});3. 然后按住回车&#xff08;有 conform 弹框需要确认&#xff09;&#xff0c;等待全部清空

golang的jwt学习笔记

文章目录 初始化项目加密一步一步编写程序另一个参数--加密方式关于StandardClaims 解密解析出来的怎么用关于`MapClaims`上面使用结构体的全代码实战项目关于验证这个项目的前端初始化项目 自然第一步是暗转jwt-go的依赖啦 #go get github.com/golang-jwt/jwt/v5 go get githu…

Ubuntu根目录下各文件夹的功能详细介绍

Ubuntu的根目录下存在着很多的文件夹&#xff0c;但你知道他们都存放着哪些文件呢&#xff1f;这些是深入了解Ubuntu系统必不缺少的知识&#xff0c;本文就关于此做一下介绍吧。 /bin/ 用以存储二进制可执行命令文件。 /sbin/ 许多系统命令的存储位置&#xff0c;/usr/sb…

mock测试使用断言_使用自定义断言丰富测试代码

mock测试使用断言受GeeCON会议期间tkaczanowski演讲的启发&#xff0c;我决定仔细研究AssertJ库的自定义断言。 在我的“骰子”游戏中&#xff0c;我创建了一个“机会”&#xff0c;它是骰子的任何组合&#xff0c;其分数是所有骰子的总和。 这是相对简单的对象&#xff1a; …

如何实现有序列表端内换行

背景 有序列表换行后自动开启下一个标号&#xff0c;让人苦恼。 操作 操作系统换行操作 1. 【Enter】键是硬回车&#xff0c;即段落标记。回车后文字属于下一段落 2. 【shiftEnter】是软回车快捷键。即人工换行符。回车后文字仍属于前一段落&#xff0c;只不过重新换行。 …

Java性能:For-eaching与Streaming

在for循环中向上或向下计数是最有效的迭代方式吗&#xff1f; 有时答案既不是。 阅读这篇文章&#xff0c;了解不同迭代品种的影响。 迭代性能 关于如何以高性能进行迭代有很多观点。 Java中的传统迭代方式是一个for循环&#xff0c;该循环从零开始&#xff0c;然后计数到一些…

好用的截图工具

目录 截图软件介绍 神器2——Snipaste PicPick——自带画图 LightShot——自带图床 功能总结 截图软件介绍 参考推荐5个截图工具&#xff08;超好用&#xff09; - 知乎&#xff0c;列出几个好用的截图工具 神器2——Snipaste 超级好用&#xff0c;QQ的功能Snipaste全都有…

Markdown语法与文本内容冲突的解决方案(软件Typora)

背景 使用Typora输入文字后&#xff0c;其中特殊字符自动识别为Markdown语法 解决方式 在使用markdown书写博客时&#xff0c;有可能会出现文本中的字符是markdown语法&#xff0c;那么markdown翻译器就会误将这些符号也翻译成某种功能&#xff0c;就会出现显示错误的情况。…

如何在Flutter(REST API)中进行API调用

在本文中&#xff0c;我们将探讨如何在波动中进行API调用并使用简单的REST API。 在这里查看我在Flutter上的其他一些帖子&#xff1a; Flutter vs React Native 了解Flutter中的BLoC架构 &#xff08;强烈建议&#xff09; 在Flutter中构建ListView&#xff08;RecyclerVi…

sublime关闭左边文件路径快捷键

目录 背景 解决方法 方案一&#xff1a; 方案二&#xff1a; 背景 sublime查看某一文件具体内容&#xff0c;左边文件路径占用一部分空间&#xff0c;影响观看 解决方法 方案一&#xff1a; 使用快捷键&#xff1a;关闭和打开相同&#xff0c;先按 CtrlK&#xff0c;再按…

Typora全局搜素

目录 背景 解决方式 全局文件夹下搜索 方法一 方法二 单一文件下搜索 查找功能 1 查找整个单词 ​2 区分大小写 背景 有时需要在打开的文件夹中所有文件搜索某一单词&#xff0c;有时需要在一个文件下搜索 解决方式 全局文件夹下搜索 方法一 方法二 快捷键&#x…

linux 内存不足杀进程_内存不足:杀死进程或牺牲孩子

linux 内存不足杀进程现在是早上六点。 我清醒地总结了导致我太早唤醒电话的事件顺序。 这些故事开始时&#xff0c;我的电话警报响了。 困倦而脾气暴躁的我检查了电话&#xff0c;看我是否真的疯了以至于无法在凌晨5点设置唤醒警报。 不&#xff0c;这是我们的监视系统&#x…

为什么声明性编码使您成为更好的程序员

在许多情况下&#xff0c;具有功能组成的声明式解决方案提供了优于传统命令式代码的优越代码度量。 阅读本文并了解如何使用具有功能组成的声明性代码成为更好的程序员。 在本文中&#xff0c;我们将仔细研究三个问题示例&#xff0c;并研究用于解决这些问题的两种不同技术&am…

Ubuntu 16.04设置IP、网关、DNS

说明&#xff1a;在网上给的教程上面通常会有这样的一个误导思路&#xff0c;按照配置文件设置后会不生效的问题&#xff0c;甚至没有一点效果&#xff0c;经过排查发现Linux下设置IP这个话题的入口线索应该分为两种&#xff1a;1为Server版&#xff0c;2为Desktop版&#xff0…

eclipse调试NS3

Tips&#xff1a; 1&#xff0c; 安装eclipse时注意选择C开发组件&#xff1b; 环境配置参考&#xff1a;https://www.cnblogs.com/zlcxbb/p/3852810.html 第一步&#xff0c;新建C工程&#xff1b; 第二步&#xff0c;在project explorer中右键属性&#xff0c;如下图&…

高效的企业测试-单元和用例测试(2/6)

在本系列的第一部分中&#xff0c;我们看到了有效测试应满足的一些普遍适用的原则和约束。 在这一部分中&#xff0c;我们将仔细研究代码级单元测试以及组件或用例测试。 单元测试 单元测试验证单个单元&#xff08;通常是类&#xff09;的行为&#xff0c;而忽略或模拟该单元…

sublime text 光标移动行末/行首

背景 使用Sublime有移动至行首与文件首部的需求 解决方式 sublime text没有直接跳转至行首行尾的&#xff0c;因为不能判断哪里是段首和短位。但可以通过连续移动单词的方式快速到达行首或行尾。 快捷键 左键 // 向左移动一个字母 右键 // 向右移动一个字母 ctrl左键 //…

Typora文件快速打开与关闭文件

背景 Typora快速关闭与打开某个文件 快捷键 关闭&#xff1a; Ctrl W 在文件中打开&#xff1a; Contrl O 从相关历史记录中快速打开&#xff1a; Ctrl P 保存&#xff1a;CtrlS 另存为&#xff1a;CtrlShiftS 新建窗口&#xff1a;CtrlN

搜狗输入法更换字体与皮肤

图标上右键-更多-属性设置 效果&#xff1a; 注意&#xff1a;如果是新安装的字体&#xff0c;更换中文字体但其中列表没有显示&#xff0c;可以取消更换字体前面的对钩后&#xff0c;重新选择对钩&#xff0c;此时就显示新的中文字体了