当前位置: 首页 > news >正文

什么是Mock?为什么要使用Mock呢?

1、前言

在日常开发过程中,大家经常都会遇到:新需求来了,但是需要跟第三方接口来对接,第三方服务还没好,我们自己的功能设计如何继续呢?这里,给大家推荐一下Mock方案。

2、场景示例

2.1、场景一:公司外部间的接口调用

我们都知道,联调外部接口,往往都需要申请测试环境,而申请外部测试环境的时间往往都很长、会耗费很多精力。当然,一般都是项目经理去协调的,但是作为有担当的开发人员,不可能在这个空窗期摸鱼划水吧。不然,等环境下来之后,可就是自己苦日子的开始,毕竟,不催工期的项目经理还是少见的。

2.2、场景二:公司内部之间的接口调用

曾经有一个项目需要我们配合另一个部门一起做。需求宣讲完后就是定排期,然后我们就问合作部门:“这几个接口什么时候可以联调?”

因为合作部门还在赶另外一个项目,便回复道:“我们先一起对接口,等忙完手头这个项目,再给出排期可以吗?”

然后我们催促道:“那也得给出一个具体的上线计划啊?”

在我们的催促下,合作部门终于给出了一个日期。

过了几天,合作部门手头的项目出现了延期,又跑过来跟我们说:“我们可能晚几天才能提供那些接口。”

因为需要与对方交互的接口的功能迟迟未动,我们也不敢释放人手,担心人手释放后,项目又立马启动,开发人员好不容易熟悉了新项目又要回来做这个。

为此,我们坐在一起商量了一个解决思路:

3、解决思路

我们希望有一个 Mock 接口服务,它能提供与正式服务的 URI、出入参一样的接口,区别是主机名或者 URL 的前缀不一样。

在开发和测试过程中,我们都连接上 Mock 服务。等到接口或环境搭建好后,我们无须修改代码,通过一个简单的配置切换即可让服务连接到真实接口服务,然后通过一些简单的回归测试即可实现上线,大大提升了开发效率,此时整体的系统架构如下图所示:

alt

不过,如果我们想实现这一思路,可就一点不简单了,因为他包含了Mock服务端和Mock服务客户端调用设计。

4、Mock服务端设计

先说下在Mock服务端设计过程中,都需要满足哪些需求?

4.1、Mock接口支持返回动态字段数据

比如有个接口输入的参数为userId、orderid、redirectUrl,如下所示:

alt 输出参数为success和startTime,如下所示:

alt 我们希望每次调用这个Mock接口时,startTime都返回当前时间,如:

{
success:true,
startTime:2023-11-12 12:45:02
}

4.2、Mock接口支持一些简单逻辑

在测试过程中,我们会通过不同的测试用例走完不同的流程。

紧接着上面的例子,比如我们希望调用 Mock 接口传入的 UserID 是 10001,那么 Mock 接口返回的 success 值为 True,否则为 False,而后系统会根据不同的 success 值进入不同的流程。

4.3、Mock接口支持回调

在实际开发工作中,有很多联调接口需要异步回调,比如上面的例子中,如果返回的 success 值是 True,我们希望过一段时间回调 Redirect URL。

4.4、Mock接口支持规则校验

我们希望通过添加一些规则让这个 Mock 服务对传入的参数进行校验,比如校验 UserID 是否为数字、OrderID 是否为 15 位数字、Redirect URL 是否为 URL……

4.5、Mock接口支持接口文档导入

这一点比较特别,比如某些团队在设计接口文档时,直接将接口定义放在 Wiki 上;而某些团队直接写在 Java 代码中,再通过 Swagger 生成在线接口文档。

对于前者,我们要求定义接口时,直接将接口文档放在新的 Mock 服务上。而对于后者,因为不想改变他们的习惯,所以最终 Mock 服务需要支持 Swagger 文档导入。

根据以上五点需求,我们开始在市面上找一些合适的开源框架,并发现市面上收费的接口文档管理工具有 Apizza、Eolinker,免费的有 YAPI 和 RAP2,出于各种原因的考虑,最终我们决定在 YAPI 和 RAP2 中进行选择。

这里我们可以看一下YAPI和RAP2对比:

alt 通过表中的内容对比,很明显YAPI更符合我们的需求。因此,在Mock服务端设计过程中,我们选择基于YAPI进行二次开发。

5、Mock服务客户端调用设计

说完Mock服务端,接下来我们看看调用Mock服务客户端时,都需要考虑什么?

5.1、Mock服务如何支持基于二进制流的接口调用?

因为历史原因,有些服务间调用使用 Spring Cloud Feign ,而有些服务间调用使用基于二进制流序列化的 RPC(当然是基于 TOP 协议)。

我们知道,如果服务间的通讯是基于二进制流而不是 JSON,就没办法在 YAPI 上通过简单的界面定义输入输出参数了,且 YAPI 也不支持二进制流的调用,此时我们的解决方案如下图所示:

alt 在上面框架中,我们添加了一个拦截器,它会拦截所有服务间调用的请求,并增加一个判断。如果访问的地址是 Mock 服务,我们就使用 HTTP 协议,并且通过 JSON 进行序列化和反序列,这样问题就解决了。

这里,我们需要补充一点:曾经,我还碰到过一些第三方接口使用 XML 格式(很多银行的接口就是这样),最终我们决定先不支持自定义XML格式的接口,因为改造 YAPI 的工作量实在太大。

5.2、Mock服务客户端如何简单切换Mock与真实服务?

这里,我们需要考虑以下两种情况:

  • 对于第三方接口,我们只需在配置中将第三方接口的 host 改为 Mock 服务的 host 即可。
  • 对于微服务间的调用,我们知道 Spring Cloud 中的微服务定义都是服务级别,但是在实际开发的场景中,我们需要使用接口级别的 Mock,比如我们开发的 operationService,它依赖 productService 的几个接口。因此,在新项目中,我们还需要在 productService 中新增几个接口,且它们必须调用 Mock 服务的接口,而原先的接口继续调用真实的 productService 中原来已经做好的接口。此时,我们需要在配置中心增加 2 个配置项:mock.apis 和 mock.host,每次服务间调用时,先判断调用的 URI 是否在 mock.apis 字符串列表中,如果在,则让它调用 mock.host 这台机器。特别说明一点:关于这点,曾经我们也出过错。因为在上线时配错了 mock.apis 和 mock.host,导致线上环境使用了 Mock 服务的情况,所以我们需要多考虑下面这点。

5.3、如何预防线上环境使用Mock服务?

对于此问题,我们做了一个检查代码:在服务启动时,先判断当前的环境名称,如果是 prod(线上环境),先判断 mock.apis 中是否有值,有值的话提示异常。然后扫描所有的 properties 配置,如果配置中包含 Mock 服务地址,则说明有些地方配置了 Mock 服务的调用,也提示异常。

到这里,整体的 Mock 调用方案就完成了。

以上,就是关于Mock服务端与客户端的设计与实现思路,有更好的方案或思路, 可以联系我哦:

微信公众号:服务端技术精选

淘宝小店:淘宝小店

个人小网站:小网站

本文由 mdnice 多平台发布

相关文章:

  • GEM5 Garnet DVFS / NoC DVFS教程:ruby.clk_domain ruby.voltage_domain
  • squid代理服务器
  • 深入解析序列模型:全面阐释 RNN、LSTM 与 Seq2Seq 的秘密
  • js 对象数组删除某一个特定的对象
  • 数据结构八种内部排序算法c++实现
  • 【Java 进阶篇】Ajax 实现——JQuery 实现方式 `get` 与 `post`
  • MySQL中json类型,你使用过吗
  • R语言:利用biomod2进行生态位建模
  • 【数据结构初阶】双链表
  • React整理总结(四)
  • 深度学习之基于YoloV5-Pose的人体姿态检测可视化系统
  • m1 rvm install 3.0.0 Error running ‘__rvm_make -j8‘
  • 2023.11.18 -自用hadoop高可用环境搭建命令
  • git常用命令和参数有哪些?【git看这一篇就够了】
  • USB转CAN的使用说明
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • Apache的80端口被占用以及访问时报错403
  • download使用浅析
  • Go 语言编译器的 //go: 详解
  • JavaScript 奇技淫巧
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • node.js
  • windows下mongoDB的环境配置
  • 电商搜索引擎的架构设计和性能优化
  • 分类模型——Logistics Regression
  • 给Prometheus造假数据的方法
  • 用Canvas画一棵二叉树
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • ​flutter 代码混淆
  • ​Java并发新构件之Exchanger
  • ​力扣解法汇总946-验证栈序列
  • ​批处理文件中的errorlevel用法
  • #define用法
  • #define与typedef区别
  • #QT项目实战(天气预报)
  • (1)SpringCloud 整合Python
  • (3)nginx 配置(nginx.conf)
  • (办公)springboot配置aop处理请求.
  • (差分)胡桃爱原石
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (译) 函数式 JS #1:简介
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • (转)3D模板阴影原理
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .NET : 在VS2008中计算代码度量值
  • .NET 中让 Task 支持带超时的异步等待
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET教程 - 字符串 编码 正则表达式(String Encoding Regular Express)
  • @ResponseBody
  • [ linux ] linux 命令英文全称及解释
  • [30期] 我的学习方法
  • [BZOJ4010]菜肴制作
  • [C++]——带你学习类和对象
  • [CISCN2019 华东南赛区]Web4