微服务带来的测试复杂性
在微服务架构中,服务之间会相互交互以实现某些业务能力。例如,服务A为了完成某项工作,会调用服务B以获取某些数据协助其完成工作。
这种类型的系统给测试带来了复杂性上的挑战。在典型的端到端测试用例中,客户端对某几个服务进行了调用,而这些服务又对其它服务进行了调用。经过层层传递,客户端和所有后端服务上的可传递闭包一起形成了巨型的拓扑图依赖。
所以,你以为的服务B,其实背后是一整个宇宙...
就像两个人谈朋友一样,一开始以为就是两个人之间的事情,等到结婚之后才发现,真正是两个家庭的事情。在某些地方,甚至是两个宗族之间的事情。
又例如“六度关系理论“所说的,你和世界上任何人之间所间隔的关系不会超过六度,也就是说最多通过六个人你就能够认识任何一个陌生人。
扯远了。
总之,会涉及到很多人。
因此即使是完成一个最为简单的测试或者调试工作,处于依赖路径上的所有这些服务都必须启动并正确运行。这种复杂性带来的问题是后台的功能自动化测试用例不好写、不稳定,维护成本高。
首先,能够快速、低成本地拥有一套包含了整个巨型拓扑图的测试环境就是一件令人头疼的事情。如果还要求这个环境能是独占式的,可以规避使用者的冲突,那就更是高成本了。
基本上,你拥有了创造平行宇宙的能力。
另外,这个宇宙系统中的所有服务随时可能升级。可能要使用其他团队正在开发中的版本才能与被测试的服务进行联调,而不是现有的线上环境版本。
从数据的角度来讲,为了能够给被测服务提供所需要的的测试数据,可能需要在依赖拓扑的某些服务中来准备数据。而测试人员是否具备下游隐含依赖服务的能力,从而可以制造和管理所需要的数据是一项巨大的挑战。特别是微服务所宣称的让团队只关注自身服务的口号相去甚远。
如果普通测试人员还是需要具备了解全局的能力,这样的要求就非常高了。
那是上帝视角了。
测试挡板,也就是API模拟工具(API mocking tools),或者所谓的服务虚拟化工具(service virtualization tools ),作为微服务测试中的必备基础设施,正是用来解决上述问题的解决方案之一。
来看一下通过引入测试挡板工具后的微服务下的极简使用场景,
1)还是有2个微服务A和B,A将调用 B完成某项工作。
2)测试用例创建-使用测试挡板将A调用B的请求/响应流量进行捕捉。
3)测试用例执行-在B离线的情况下,运行上述测试用例,测试挡板充当B的测试桩完成用例的正常运行。
这是最基本的API挡板的应用场景,通过录制、回放来实现A、B两个服务在测试过程中的解耦,极大降低了A服务测试的复杂度。
而在此类工具的选型和向开发团队推广过程中,收集到过以下的一些问题和痛点,
前两条其实是推广和实施测试挡板的切入点,也是此类工具优于Mockito等模拟工具的重要卖点。后两条主要是针对开发人员使用挡板类工具时所需要注意的特点。这和针对系统测试或者专职测试人员的测试挡板需求还是有差异的。
在了解了上述问题之后,再来进行工具选型时就会发现,大部分的测试挡板类的工具,如WireMock、Moco等,虽然功能很强大,但是要么是更为擅长作为独立部署的挡板工具,或者是在自动录制回放的细节方面与Hoverfly略有差异。最终笔者还是向各个开发团队推荐了Hoverfly这个工具。
自动切换捕捉和回放的Hoverfly
首先来看一下以下的案例,
@HoverflySimulate(source = @Source(
value = simulation.json", type = SourceType.FILE),
enableAutoCapture = true)
@ExtendWith(HoverflyExtension.class)
class CaptureIfFileNotPresent {
// ...
}
这是Hoverfly-java提供的一个Capture or simulate案例,也是Hoverfly在琳琅满目的测试挡板类工具库凭借着这一点成功吸引到笔者的原因之一。
可以看到,整个过程只要在类上添加相关的Hoverfly注解进行配置,申明相关的文件以及是否启用自动捕捉的功能,就可以完成HTTP请求的捕捉、落成文件。这是首次测试用例首次执行时的场景。
而当需要再次执行时,由于该文件已经就绪,Hoverfly将启动回功能,通过捕捉请求,给测试套件提供外部服务的模拟返回。
整个过程无需手工编写额外的请求、响应文件,或者是编写类似
capture.start()
//test
capture.stop()
这样的脚手架代码来实现HTTP请求的捕捉,以及再人工拆除上述代码,将用例转换成回放模式,用于后续的用例执行。对于开发人来来说,这还是有些不便的。对于已经被互联网App的极值易用性过度溺爱的用户来说,这样的不便利性在推广此类工具时有时就是一个致命的弱项。
Hoverfly的胜出就来自于这个简单的细节。
当然目前的Hoverfly-java-junit5对于增量capture还不支持,这个笔者将在下一篇文章中详细介绍。
以下是上面文字描述部分梳理出的Hoverfly的工作顺序图
为了能使用Hoverfly作为嵌入式的挡板,需要在项目中引入以下的依赖
<dependency>
<groupId>io.specto</groupId>
<artifactId>hoverfly-java</artifactId>
<version>0.13.0</version>
<scope>test</scope>
</dependency>
Hoverfly提供的这个Java语言包可以供开发人员在JAVA环境下使用,包括了,
至此,关于Hoverfly的第一篇文章就先结束了。后续笔者将介绍在实际项目中使用和推广Hoverfly-java-juit5时的一些实际案例和排坑经验。
未完待续