wiremock 使用_使用WireMock进行更好的集成测试

wiremock 使用

无论您是遵循传统的测试金字塔还是采用诸如“ 测试蜂窝”这样的较新方法,都应该在开发过程中的某个时候开始编写集成测试。

您可以编写多种类型的集成测试。 从持久性测试开始,您可以检查组件之间的交互,也可以模拟调用外部服务。 本文将讨论后一种情况。 在谈论WireMock之前,让我们从一个激励性的例子开始。

ChuckNorrisFact服务

完整的示例可以在GitHub上找到 。

在以前的博客文章中,您可能已经看到我使用Chuck Norris事实API 。 该API将为我们提供实现所依赖的另一项服务的示例。 我们有一个简单的ChuckNorrisFactController作为用于手动测试的API。 旁边的“业务”类存在ChuckNorrisService ,做调用外部API。 它使用Spring的RestTemplate 。 没什么特别的。 我多次看到的是模拟RestTemplate并返回一些预先确定的答案的测试。 该实现可能如下所示:

 @Service  public class ChuckNorrisService{  ... public ChuckNorrisFact retrieveFact() { ResponseEntity<ChuckNorrisFactResponse> response = restTemplate.getForEntity(url, ChuckNorrisFactResponse. class ); return Optional.ofNullable(response.getBody()).map(ChuckNorrisFactResponse::getFact).orElse(BACKUP_FACT); } ... } 

在检查成功案例的常规单元测试旁边,至少会有一个覆盖错误案例的测试,即4xx或5xx状态代码:

 @Test public void shouldReturnBackupFactInCaseOfError() { String url = " http://localhost:8080 " ; RestTemplate mockTemplate = mock(RestTemplate. class ); ResponseEntity<ChuckNorrisFactResponse> responseEntity = new ResponseEntity<>(HttpStatus.SERVICE_UNAVAILABLE); when(mockTemplate.getForEntity(url, ChuckNorrisFactResponse. class )).thenReturn(responseEntity); var service = new ChuckNorrisService(mockTemplate, url); ChuckNorrisFact retrieved = service.retrieveFact(); assertThat(retrieved).isEqualTo(ChuckNorrisService.BACKUP_FACT); } 

看起来还不错吧? 响应实体返回503错误代码,我们的服务不会崩溃。 所有测试都是绿色的,我们可以部署我们的应用程序。

不幸的是,Spring的RestTemplate不能这样工作。 getForEntity的方法签名为我们提供了一个非常小的提示。 它指出throws RestClientException 。 这就是模拟的RestTemplate与实际实现不同的地方。 我们将永远不会收到带有4xx或5xx状态代码的ResponseEntity 。 RestTemplate将抛出一个子类 RestClientException 。 通过查看类的层次结构,我们可以对可能抛出的结果有一个很好的印象:


因此,让我们看看如何使这个测试更好。

WireMock进行救援

WireMock通过启动模拟服务器并返回将其配置为返回的答案来模拟Web服务。 得益于出色的DSL,它很容易集成到测试中,并且模拟请求也很简单。

对于JUnit 4,有一个WireMockRule可以帮助启动停止服务器。 对于JUnit 5,您必须自己做。 当您检查示例项目时,您可以找到ChuckNorrisServiceIntegrationTest 。 这是基于JUnit 4的SpringBoot测试。让我们来看一下。 最重要的部分是ClassRule

 @ClassRule public static WireMockRule wireMockRule = new WireMockRule(); 

如前所述,这将启动和停止WireMock服务器。 您也可以使用常规Rule来为每个测试启动和停止服务器。 对于我们的测试,这不是必需的。

接下来,您可以看到几种configureWireMockFor...方法。 这些包含WireMock何时返回答案的说明。 将WireMock配置分为几种方法并从测试中调用它们是我使用WireMock的方法。 当然,您可以在@Before方法中设置所有可能的请求。 对于成功案例,我们这样做:

 public void configureWireMockForOkResponse(ChuckNorrisFact fact) JsonProcessingException { configureWireMockForOkResponse(ChuckNorrisFact fact) throws JsonProcessingException { ChuckNorrisFactResponse chuckNorrisFactResponse = new ChuckNorrisFactResponse chuckNorrisFactResponse = ChuckNorrisFactResponse( "success" , fact); stubFor(get(urlEqualTo( "/jokes/random" )) .willReturn(okJson(OBJECT_MAPPER.writeValueAsString(chuckNorrisFactResponse)))); } 

所有方法都是从com.github.tomakehurst.wiremock.client.WireMock静态com.github.tomakehurst.wiremock.client.WireMock 。 如您所见,我们将HTTP GET存入路径/jokes/random并返回JSON对象。 的
okJson()方法只是JSON内容的200个响应的简写。 对于错误情况,代码甚至更简单:

 private void configureWireMockForErrorResponse() { stubFor(get(urlEqualTo( "/jokes/random" )) .willReturn(serverError())); } 

如您所见,DSL使阅读说明变得容易。

将WireMock放置在适当的位置,我们可以看到我们先前的实现不起作用,因为RestTemplate引发了异常。 因此,我们必须调整代码:

 public ChuckNorrisFact retrieveFact() { try { ResponseEntity<ChuckNorrisFactResponse> response = restTemplate.getForEntity(url, ChuckNorrisFactResponse. class ); return Optional.ofNullable(response.getBody()).map(ChuckNorrisFactResponse::getFact).orElse(BACKUP_FACT); } catch (HttpStatusCodeException e){ return BACKUP_FACT; } } 

这已经涵盖了WireMock的基本用例。 配置请求的答案,执行测试,检查结果。 就这么简单。

但是,在云环境中运行测试时,通常会遇到一个问题。 让我们看看我们能做什么。

动态端口上的WireMock

您可能已经注意到,项目中的集成测试包含一个
ApplicationContextInitializer类及其@TestPropertySource批注将覆盖实际API的URL。 那是因为我想在随机端口上启动WireMock。 当然,您可以为WireMock配置一个固定端口,并在测试中将此端口用作硬编码值。 但是,如果您的测试在某些云提供商的基础架构上运行,则无法确定端口是否可用。 因此,我认为随机端口更好。
不过,在Spring应用程序中使用属性时,我们必须以某种方式将随机端口传递给我们的服务。 或者,如您在示例中看到的那样,覆盖URL。 这就是为什么我们使用ApplicationContextInitializer 。 我们将动态分配的端口添加到应用程序上下文中,然后可以使用属性来引用它 ${wiremock.port} 。 这里唯一的缺点是我们现在必须使用ClassRule。 否则,我们无法在初始化Spring应用程序之前访问端口。 解决了此问题后,让我们看一下涉及HTTP调用的一个常见问题。

超时时间

WireMock提供了更多的响应可能性,而不仅仅是对GET请求的简单答复。 经常被遗忘的另一个测试案例是测试超时。 开发人员往往会忘记在RestTemplate甚至URLConnections上设置超时。 如果没有超时,则两者都将等待无限量的时间进行响应。 在最好的情况下,您不会注意到,在最坏的情况下,所有线程都将等待永远不会到达的响应。

因此,我们应该添加一个模拟超时的测试。 当然,我们也可以使用Mockito模拟来创建延迟,但是在这种情况下,我们将再次猜测RestTemplate的行为。 使用WireMock模拟延迟非常简单:

 private void configureWireMockForSlowResponse() throws JsonProcessingException { ChuckNorrisFactResponse chuckNorrisFactResponse = new ChuckNorrisFactResponse chuckNorrisFactResponse = ChuckNorrisFactResponse( "success" , new ChuckNorrisFact(1L, "" )); stubFor(get(urlEqualTo( "/jokes/random" )) .willReturn( okJson(OBJECT_MAPPER.writeValueAsString(chuckNorrisFactResponse)) .withFixedDelay(( int ) Duration.ofSeconds(10L).toMillis()))); } 

withFixedDelay()需要一个表示毫秒的int值。 我更喜欢使用Duration或至少一个表示该参数表示毫秒的常量,而不必每次都读取JavaDoc。

RestTemplate上设置超时并添加响应缓慢的测试后,我们可以看到RestTemplate抛出ResourceAccessException 。 因此,我们可以调整catch块以捕获此异常和HttpStatusCodeException也可以仅捕获两者的超类:

 public ChuckNorrisFact retrieveFact() { try { ResponseEntity<ChuckNorrisFactResponse> response = restTemplate.getForEntity(url, ChuckNorrisFactResponse. class ); return Optional.ofNullable(response.getBody()).map(ChuckNorrisFactResponse::getFact).orElse(BACKUP_FACT); } catch (RestClientException e){ return BACKUP_FACT; } } 

现在,我们已经很好地介绍了执行HTTP请求时最常见的情况,并且可以确定我们正在测试接近真实条件的条件。

为什么不飞翔?

HTTP集成测试的另一个选择是Hoverfly 。 它的工作方式类似于WireMock,但我更喜欢后者。 原因是在运行包含浏览器的端到端测试时,WireMock也非常有用。 Hoverfly(至少是Java库)受JVM代理的限制。 这可能使它比WireMock更快,但是当例如某些JavaScript代码开始起作用时,它根本不起作用。 当您的浏览器代码也直接调用其他一些服务时,WireMock启动Web服务器这一事实非常有用。 然后,您也可以使用WireMock来模拟它们,并编写例如Selenium测试。

结论

我希望本文可以向您展示两件事:

  1. 集成测试的重要性
  2. WireMock非常好

当然,这两个主题都可以填满更多文章。 尽管如此,我还是想让您了解如何使用WireMock及其功能。 随时检查他们的文档,然后尝试更多其他事情。 例如,也可以使用WireMock测试身份验证。

翻译自: https://www.javacodegeeks.com/2019/11/better-integration-tests-with-wiremock.html

wiremock 使用

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

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

相关文章

mysql备份七牛云存储_定时备份 Mysql并上传到七牛的方法

多数应用场景下&#xff0c;我们需要对重要数据进行备份、并放置到一个安全的地方&#xff0c;以备不时之需。常见的 MySQL 数据备份方式有&#xff0c;直接打包复制对应的数据库或表文件(物理备份)、mysqldump 全量逻辑备份、xtrabackup 增量逻辑备份等。常见的数据存储方式有…

jetty java_Jetty,Java和OAuth入门

jetty java使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证&#xff0c;管理和保护。 今天尝试Okta。 Jetty是一个小型&#xff0c;高度可扩展的基于Java的Web服务器和servlet引擎。 它支持HTTP / 2&#xff0c…

DFS应用——查找强分支

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “DFS应用——查找强分支” 的idea 并用源代码加以实现 &#xff1b; 【1】查找强分支 1.1&#xff09;如何检测一个图是否是强连通的&#xff1a; 通过执行两…

python中的super用法详解_Python中super函数用法实例分析

本文实例讲述了python中super函数用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简单说, super函数是调用下一个父类(超类)并返回该父类实例的方法. 这里的下…

java 管理多个进程_管理多个Java安装

java 管理多个进程随着越来越多的Java版本发布&#xff0c;在本地环境中管理多个Java安装将变得更加有趣。 不同的项目可能需要不同的Java版本。 jenv项目是管理Java安装的便捷方法。 它可以在全局&#xff0c;目录和外壳程序级别上设置本地Java安装&#xff0c;并使用易于记忆…

NP-完全性介绍

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 旨在 理解 “NP-完全性” 的idea &#xff1b; 【1】难与易 1.1&#xff09;不可判定问题&#xff1a;正如实数不足以表示 x^2 < 0 的解那样&#xff0c;可以证明&#xff0c; 计算机不可能解决碰…

python发邮件给多个人发送消息_python发送邮件(带附件)、发送给多人、抄送给多人的示例...

python发送邮件(带附件)、发送给多人、抄送给多人的示例#!/usr/bin/env python# -*-encoding: utf-8 -*-import smtplibfrom email.mime.multipart import MIMEMultipartfrom email.mime.text import MIMEText#image包可以发送图片形式的附件# from email.mime.image import MI…

camel apache_Apache Camel 3只有2个月的路程

camel apache骆驼队正忙于为 Apache Camel 3.今天&#xff0c;第二个候选版本已构建并发布在暂存库中&#xff0c;供早期的适配器尝试 。 当我自己很忙的时候&#xff0c;我只想写一篇简短的博客文章&#xff0c;以使社区了解Apache Camel 3即将发布&#xff0c;并且我们希望…

浅谈java代理

【0】README 0.1&#xff09; 本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理解 java代理机制 的基础知识&#xff1b; 【1】代理相关 1.1&#xff09;利用代理可以在运行时创建一个实现了一组给定接口的新类&#xff0c; 这种功能只有在 编译时无法确定需要实…

织梦mysql安装教程视频教程_织梦DedeCMSV6系统安装步骤教程

DedeCMSV6系统基于PHP7.*MySQL开发&#xff0c;本篇文档将介绍如何下载DedeCMSV6系统&#xff0c;并且通过之前已经部署好的系统环境来安装配置一个安全的站点。准备工作&#xff1a;主机一台(PHP7.0以上MYSQL)域名(做好解析绑定工作)源码下载通过DedeCMSV6系统下载页面可以获取…

无法创建t的通用数组_创建通用数组的问题

无法创建t的通用数组在这篇文章中&#xff0c;我们将介绍一篇全面的文章&#xff0c;其中介绍了创建通用数组的问题。 Java编程语言于2004年9月在Java 5.0“ Tiger”发行版中添加了泛型。 泛型或类型参数化系统在提供类型安全性的同时扩展了Java现有的类型系统。 1.简介 Java具…

贪婪算法+小应用(调度问题)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 旨在 理解 “DFS应用——贪婪算法” 的idea&#xff1b; 【1】贪婪算法 1.1&#xff09;已经看到的三个贪婪算法&#xff1a; Dijkstra算、Prim算法 和 Kruskal 算法&#xff1b;&#xff08;Dijkstr…

http 安全性和幂等性_HTTP方法:幂等性和安全性

http 安全性和幂等性幂等性和安全性是HTTP方法的属性。 HTTP RFC定义了这些属性&#xff0c;并告诉我们哪些HTTP方法是安全且幂等的。 服务器应用程序应确保正确执行安全和幂等的语义&#xff0c;如客户端期望的那样。 安全的HTTP方法 如果HTTP方法不更改服务器状态&#xff0…

Huffman编码(Huffman树)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “Huffman编码&#xff08;Huffman树&#xff09;” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; Huffman树的构建算法属于 贪婪算法&#xff0c;…

java获取文件列表_java获取指定目录中的文件列表

最近项目中会动态生成文件html及相关资源文件(css,js,png,mp3)&#xff0c;为了防止文件名重复&#xff0c;需要获取目录中相同类型文件的最大编号&#xff0c;下面我用代码来实现获得文件列表。public static void getFiles(String path) {File file new File(path);// 如果这…

jep290涉及jdk版本_针对JDK 14提议的另外六个JEP

jep290涉及jdk版本Mark Reinhold最近的消息宣布了六个新的“建议针对JDK 14的JEP ”&#xff1a; JEP 345 &#xff0c; JEP 361 &#xff0c; JEP 363 &#xff0c; JEP 364 &#xff0c; JEP 365和JEP 367 。 假设没有异议由11月7日提出&#xff0c;这些JEPs将有针对性地JDK …

近似装箱问题(三种联机算法实现)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “近似装箱问题&#xff08;三种联机算法实现&#xff09;” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 近似装箱问题的三种联机算法 分别是&am…

java 随机数种子_Java--随机数和随机数种子(转)

在计算机中并没有一个真正的随机数发生器&#xff0c;但是可以做到使产生的数字重复率很低&#xff0c;这样看起来好象是真正的随机数&#xff0c;实现这一功能的程序叫伪随机数发生器。有关如何产生随机数的理论有许多&#xff0c;如果要详细地讨论&#xff0c;需要厚厚的一本…

java 堆转储快照_捕获Java堆转储的7个选项

java 堆转储快照堆转储是诊断与内存相关的问题的重要工件&#xff0c;例如内存泄漏缓慢&#xff0c;垃圾回收问题和java.lang.OutOfMemoryError。它们也是优化内存消耗的重要工件。 有很棒的工具&#xff0c;例如Eclipse MAT和Heap Hero&#xff0c;可以分析堆转储。 但是&…

java 提取url参数_Java提取URL某个参数的值

ASP&period;NET Core 中文文档 第四章 MVC(4&period;3)过滤器原文:Filters 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:何镇汐 ASP.NET MVC 过滤器 可在执行管道的前后特定阶段执行代码.过滤器可以配置为全局有效.仅对控 ...jquery插件-表单提交插件-jQuery&peri…