考虑一个负责进行远程调用和获取详细信息的服务类:

 ...  public class CitiesService { private final WebClient.Builder webClientBuilder; private final String baseUrl; public CitiesService( WebClient.Builder webClientBuilder, @Value ( "${cityservice.url}" ) String baseUrl) { "${cityservice.url}" ) String baseUrl) { this .webClientBuilder = webClientBuilder; this .baseUrl = baseUrl; } public Flux<City> getCities() { return this .webClientBuilder.build() .get()  .... 

这是一个Spring Bean,它通过称为“ cityservice.url”的属性来解析要调用的URL。

如果我想测试此类,则在使用WebClient时一直使用的方法是使用出色的Wiremock启动模拟服务器,并使用它来测试此类。 Wiremock模拟看起来像这样:

 private static final WireMockServer WIREMOCK_SERVER = new WireMockServer(wireMockConfig().dynamicPort()); ..... WIREMOCK_SERVER.stubFor(get(urlEqualTo( "/cities" )) .withHeader( "Accept" , equalTo( "application/json" )) .willReturn(aResponse() .withStatus( 200 ) .withHeader( "Content-Type" , "application/json" ) .withBody(resultJson))); 

Wiremock服务器正在一个随机端口上启动,并设置为响应名为“ / cities”的终结点。 这是鸡肉和鸡蛋问题的出处:

1. CitiesService类要求在开始测试之前设置名为“ cityservice.url”的属性。

2. Wiremock在一个随机端口上启动,它响应的URL是“ http:// localhost:randomport”,并且仅在测试开始后才可用。

我可以想到三种可能的解决方案来打破这种循环依赖关系:

方法1:使用硬编码端口

这种方法取决于在固定端口而不是动态端口上启动Wiremock,这样可以在启动测试时设置属性,如下所示:

 @ExtendWith (SpringExtension. class )  @SpringBootTest (classes = CitiesServiceHardcodedPortTest.SpringConfig. class , properties = "cityservice.url= http://localhost:9876 " )  public class CitiesServiceHardcodedPortTest { private static final WireMockServer WIREMOCK_SERVER = new WireMockServer(wireMockConfig().port( 9876 )); 

在此,Wiremock在端口9876上启动,并且启动时的属性设置为“ http:// localhost:9876 /”。

这解决了问题,但是,这不是CI服务器友好的,端口可能在运行时发生冲突,这导致测试不稳定。

方法2:不使用Spring进行测试

更好的方法是不使用这些属性:

 public class CitiesServiceDirectTest { private static final WireMockServer WIREMOCK_SERVER = new WireMockServer(wireMockConfig().dynamicPort()); private CitiesService citiesService; @BeforeEach public void beforeEachTest() { final WebClient.Builder webClientBuilder = WebClient.builder(); this .citiesService = new CitiesService(webClientBuilder, WIREMOCK_SERVER.baseUrl()); } 

在这里,通过在构造函数中显式设置baseUrl来创建服务,从而避免了在测试之前设置属性的需求。

方法3:应用程序上下文初始化器

ApplicationContextInitializer用于以编程方式初始化Spring Application Context,它可与测试一起使用,以在执行实际测试之前注入属性。 遵循以下原则:

 @ExtendWith (SpringExtension. class )  @SpringBootTest (classes = CitiesServiceSpringTest.SpringConfig. class )  @ContextConfiguration (initializers = {CitiesServiceSpringTest.PropertiesInitializer. class })  public class CitiesServiceSpringTest { private static final WireMockServer WIREMOCK_SERVER = new WireMockServer(wireMockConfig().dynamicPort()); @Autowired private CitiesService citiesService; @Test public void testGetCitiesCleanFlow() throws Exception { ... } static class PropertiesInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { TestPropertyValues.of( "cityservice.url=" + " http://localhost: " + WIREMOCK_SERVER.port() ).applyTo(applicationContext.getEnvironment()); } }  } 

首先启动Wiremock,然后使用初始化程序初始化Spring上下文,该初始化程序使用Wiremocks动态端口注入“ cityservice.url”属性,这种属性可用于连接到CityService。

结论

我个人更喜欢方法2,但是最好在测试之前创建Spring的连线和相关的bean,如果类利用了这些,那么我更喜欢方法3。应用程序上下文初始化器提供了一种解决鸡和蛋问题的好方法。这些属性需要在Spring的上下文参与之前提供。

所有代码示例均在此处提供:

方法1:https://github.com/bijukunjummen/reactive-cities-demo/blob/master/src/test/java/samples/geo/service/CitiesServiceHardcodedPortTest.java

方法2:https://github.com/bijukunjummen/reactive-cities-demo/blob/master/src/test/java/samples/geo/service/CitiesServiceDirectTest.java 方法3:https://github.com/bijukunjummen/reactive-cities-demo/blob/master/src/test/java/samples/geo/service/CitiesServiceSpringTest.java

翻译自: https://www.javacodegeeks.com/2019/08/chicken-egg-resolving-spring-properties-ahead-test.html

鸡肉和鸡蛋–测试前解决Spring属性相关推荐

  1. 鸡肉部位英文对照_鸡肉和鸡蛋–测试前解决Spring属性

    鸡肉部位英文对照 考虑一个负责进行远程调用和获取详细信息的服务类: ... public class CitiesService { private final WebClient.Builder w ...

  2. 解决Spring boot中读取属性配置文件出现中文乱码的问题

    解决Spring boot中读取属性配置文件出现中文乱码的问题 参考文章: (1)解决Spring boot中读取属性配置文件出现中文乱码的问题 (2)https://www.cnblogs.com/ ...

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

    2019独角兽企业重金招聘Python工程师标准>>> 简介:本文主要介绍把现今主流的springboot框架项目和精准测试工具进行结合和应用,通过精准测试的数据穿透.数据采集.测试 ...

  4. 解决Spring下无法实时访问本地静态资源

    解决Spring下浏览器无法实时访问本地静态资源 场景1:原本地文件test.json中内容为 "1".我们通过前后端交互操作,修改test.json的内容为 "2&qu ...

  5. 登录用友显示java已被阻止_解决Spring Security 用户帐号已被锁定问题

    1.问题描述 主要就是org.springframework.security.authentication.LockedException: 用户帐号已被锁定这个异常,完整异常如下: [2020-0 ...

  6. 解决spring+c3p0数据库连接一直增加的问题

    解决spring+c3p0数据库连接一直增加的问题 问题描述 spring+c3p0的配置 针对不同情况的解决方案 问题描述: SSH框架,hibernate的配置由spring接管,数据源的配置放在 ...

  7. 2.3.2 spring属性注入-注解注入-半注解注入-后序

    代码: spring属性注入-注解注入-半注解后序.zip - 蓝奏云文件大小:15.2 K|https://www.lanzouw.com/iCjbVvpvxaf 上一个博客的半注解是,一个类在xm ...

  8. Spring Security系列教程解决Spring Security环境中的跨域问题

    原创:千锋一一哥 前言 上一章节中,一一哥 给各位讲解了同源策略和跨域问题,以及跨域问题的解决方案,在本篇文章中,我会带大家进行代码实现,看看在Spring Security环境中如何解决跨域问题. ...

  9. Spring系列(九):Spring属性赋值注解@Value 用法介绍

    今天给大家分享Spring属性赋值注解@Value 用法,希望对大家能有所帮助! 1.@Value注解的作用 @Value注解的作用主要可以给属性直接赋值.也可以读取配置文件中的值给属性赋值 2.@V ...

最新文章

  1. 号外号外 你和python大牛的差距有多少?
  2. linux查看CPU信息
  3. 关于android 1.6全部的权限介绍
  4. (剑指Offer)面试题19:二叉树的镜像
  5. led流水灯——51单片机程序
  6. 第三次学JAVA再学不好就吃翔(part65)--正则表达式
  7. oracle删除定义变量,Oracle存储过程,临时表的创建、删除,变量的定义和使用
  8. Linux内存管理段页
  9. Java并发编程:从源码分析几道必问线程池的面试题?
  10. 怎样做地推,转化率提高20倍?
  11. yolov5训练自己的数据集(一文搞定训练)
  12. 简易JTAG线缆原理
  13. win10安装steam有损计算机,Win10安装steam平台提示“steam fatal error”报错的解决方法...
  14. 计量广义差分操作过程_一分钟看完计量经济学
  15. 一个离职程序员的找工作历程(2021.4.28更新)
  16. ROS学习之发布消息——Publisher_代码分析
  17. 刷cadn浏览量阅读量第二中方法
  18. 法拉科机器人接头_【发那科】图解FANUC机器人I/O信号板
  19. 数说故事全新官网2.0正式上线,全新视觉焕新升级
  20. 雷军语录:感谢“批评”让小米理性成长

热门文章

  1. ssl2863-石子合并【dp练习】
  2. 【树链剖分】LCA(P4211)
  3. Mybatis生成器插件扩展,定制方法生成,list参数生成
  4. 15个顶级Java多线程面试题及答案
  5. 架构师必须掌握的 10 条设计原则
  6. Oracle入门(十二G)之序列
  7. epoll 浅析以及 nio 中的 Selector
  8. 【Ajax】创建并封装
  9. java中判断数组中元素出现的次数
  10. jQuery最简单的留言功能^-^