微服务测试的痛点与挑战

这张图可以形象地展示单体服务和微服务的对比,单体应用就像左边巨大的集装箱,软件模块和应用都包括其中;而微服务就像是由一个小集装箱组成,微小的服务组成一个庞大、完整的系统。单体服务是一个大而全的应用体,而微服务由拆分成出来的很多小服务来组成一个庞大而完整的系统。

微服务是一种架构模式,是面向服务型架构 SOA 的一种变体,提倡将单一应用程序逐渐还原划分成小的服务,服务间互相协调、互相配合,为用户提供最终价值。微服务架构风格就是一些小而自治的服务协同工作形成松耦合的系统。另外,我们需要尽量避免一个统一的、集中式的服务管理机制,对具体的一个服务而言,应该根据上下文选择合适的语言工具对其进行构建。

结合下方的这张图,我们可以理解微服务构建的核心其实是中间领域的业务逻辑,围绕着这个领域业务逻辑,会有一些微服务去进行拆分构建。

微服务具有专注、自治、独立进程、独立部署和技术异构的特点,即每个服务只限定于特定的业务而专注做一件事情,每个服务承担的是单一职责,但是它也需要达到一定规模能够完整的处理特定的领域业务。很多人都会被微服务的“微”这个词所误导,认为微服务就是要拆分的越小越好。但是其实为了“微”而将同一领域的业务拆分到不同的服务,只会徒劳增加软件的复杂度和维护困难。

我们可以围绕应用的业务能力进行分组,每个小组的开发组人员开发微服务的技术可以不受限制。每个服务小组可以使用不同的技术架构和存储技术,有针对性地解决一些性能瓶颈问题。每个服务是互相独立部署互不影响的,这样的话我们可以实现独立打包、独立测试和独立附属,减少部署时间,提升研发效率。

微服务架构测试具有三个痛点:一、如何测试微服务的外部依赖是否正常;二、如何在微服务架构下验证系统的整个功能是否符合预期;三、这么多微服务的部署和测试,应如何开展。按照以上痛点我们可以看到,微服务测试是一种验证成本高、结果不稳定、反馈周期长的测试。

测试金字塔

测试金字塔其实是一种方法论,解决微服务测试的关键在于将微服务的测试按照不同的力度来分组。测试金字塔的概念由麦克科恩首先提出。测试是分层次的,我们看到图片左边,这个金字塔被分为三个层次,从下往上分别是单元测试、服务测试、界面测试,从下往上测试的运行速度是逐渐减慢的,外物依赖或者服务间的依赖从下到上会依赖更多。这个测试金字塔的另外一个重要特征是,从下往上对每一层的测试代码是逐层减少的。下方应该写一些小而快的测试,往上应该编写一些粗粒度的测试,编写更少的高层次测试。

然而实际中如果以这个金字塔图来作为指导,会过于笼统简单,所以我们会采用右边的分为四层的测试金字塔来做内部测试的指导思想。底层是单元测试,在这之上是集成测试,再往上是端到端的测试,顶层是探索测试。

作为开发人员或测试人员,应该关注金字塔的哪些部分呢?微服务开发人员应更多关注位于塔基底部的单元测试与集成测试。在这两层需要开发人员编写一定量的测试代码来保证覆盖,应该写许多小而快的单元测试覆盖绝大部分的业务场景,再写一定的粗粒度的集成测试,来测试重要系统之间外部依赖的交互是否正常。测试人员和质量保证人员应更多关注金字塔上面两层,测试人员可以依据 BDD 的规范来编写测试用例,用于校验系统功能的交互是否正常,还可以用非常规的手段进行破坏性的探索测试。

单元测试是测试金字塔的底基,它的定义没有标准答案。从编程角度来看,在函数式语言中我们可以认为一个函数是一个单元,在面向对象的语言中一个方法或者一个类可以表示一个单元。单元测试具有能够及时发现 bug、利于重构、保证代码质量的优势,我们系统中需要编写得最多的其实就是单元测试。

微服务的测试一般是对入栈适配器、业务逻辑和出栈适配器这三部分进行测试。入栈适配器测试的是 Controller API 是否正确;业务逻辑部分测试 Service 业务逻辑是否正确,而出栈适配器部分测试的是 SQL 逻辑是否正确。单元测试一般会遵循一个通用的 3A 结构:Arrange,Act,Assert,这样写出来的代码更有阅读性和表达力。

在微服务架构下我们所理解的集成测试是测试应用与外部依赖的集成。第三方外部服务依赖主要有两种类:第一种是微服务会依赖第三方系统的服务;第二种是系统内部的微服务与微服务之间,一种服务可能会依赖另一种微服务来实现自身逻辑。对应这两种情况会有不同的策略,第一种策略是准备真实的外部服务的依赖,第二种是使用测试替身隔绝外部依赖。进行集成测试的时候我们通常会使用一些,依赖第三方服务的话会采用 WireMock 或者 mountebank,而微服务之间的依赖调用会使用 Spring-Cloud-Contract 或者 Pact。

微服务之间的测试会使用契约测试,服务之间的接口文档就是一个契约。契约测试可以解决联调成本过高,接口变动把控困难,契约变化时提供一种可立即被服务端和消费端发现的方式,这三种痛点。契约测试的提供者指微服务接口的提供者,消费者指微服务接口的消费者。契约文件是微服务提供者和消费者共同定义的接口规范,包括接口的访问路径和输出数据。

CDC 的核心思想在于从消费者业务实现的角度出发,由消费者自己定义需要的测试数据格式以及交互细节,并驱动生成一份消费者契约。然后生产者根据契约来实现自己的逻辑,并在服务提供者端进行测试验证。契约文档应该被转换成一个存根。生产者会根据契约编写契约验证测试,契约验证测试通过会将契约文件转换为存根,存根会被消费者引用,契约的修改会导致任意一方测试的失败。这样的话可以保证契约被消费者和生产者共同遵守。

契约测试适用于微服务接口的消费者和提供者由不同的团队维护,或提供者接口被多个消费者消费这样的场景中。

端到端测试主要用于验证工作流程中的所有流程,以检查一切是否按照预期工作,确保系统以统一的方式工作,从而满足业务需求。端到端测试的难点在于安装和配置相关依赖,测试数据的自动准备二号服务的自动部署。

微服务测试蓝图

做微服务测试需要做 TDD,也就是测试在先,编码在后的开发实践。有别于以往的先编码、后测试的开发过程,而是在编程之前,先写测试脚本或设计测试用例。TDD 可以增加开发人员代码质量的信心,有利于代码设计和重构,以及快速迭代和持续交付。

微服务测试推进主要分为四步:第一步是工具,依照微服务测试层次,阶段选择合适的测试框架与工具;第二步是依据测试金字塔制定规范,贯穿生命周期始终,明确开发、测试人员的职责;第三步是自动化,贯穿 CI、CD 流程,与 DevOps 的融合;第四步是测试平台搭建,以容器化技术搭建测试平台,以 namespace 隔离不同测试环境。

点击观看完整课程视频

CODING DevOps 系列第五课:微服务测试——微服务下展开体系化的微服务测试的更多相关文章

  1. CODING DevOps 系列第三课:云计算、云原生模式下 DevOps 的建设

    本文首先会和大家分享当前整个应用生命周期的演变历程,然后讲解云计算模式下 DevOps 建设包含的过程.流程规范和标准,最后讲解云原生时代到来会带来哪些改变,以及标准化的建设会有哪些改变和突破. 应用 ...

  2. CODING DevOps 系列第四课:DevOps 中的质量内建实践

    什么是质量内建 随着时间的推移,我们项目的开发效率会逐渐降低,直到几年之后整个项目可能就无法维护,只能推倒重来.具体的表现首先就是随着时间推移,我们会发现整个需求列表里面能做的需求越来越少,因为每当我 ...

  3. CODING DevOps 系列第一课:基于开源工具链打造持续交付平台

    当下软件发展趋势 当今 IT 行业发展中比较流行的几个技术,首先是微服务化,将原有的一个系统拆分成多个,意味着有多个系统需要构建.测试.部署和运维. 第二个是敏捷开发模式,需求粒度更细化,要求一个可独 ...

  4. CODING DevOps 微服务项目实战系列第一课,明天等你

    CODING DevOps 微服务项目实战系列第一课<DevOps 微服务项目实战:DevOps 初体验>将由 CODING DevOps 开发工程师 王宽老师 向大家介绍 DevOps ...

  5. CODING DevOps 微服务项目实战系列第二课来啦!

    近年来,工程项目的结构越来越复杂,需要接入合适的持续集成流水线形式,才能满足更多变的需求,那么如何优雅地使用 CI 能力提升生产效率呢?CODING DevOps 微服务项目实战系列第二课 <D ...

  6. CODING DevOps 微服务项目实战系列最后一课,周四开讲!

    随着软件工程越来越复杂化,如何在 Kubernetes 集群进行灰度发布成为了生产部署的"必修课",而如何实现安全可控.自动化的灰度发布也成为了持续部署重点关注的问题.CODING ...

  7. CODING DevOps 代码质量实战系列最后一课,周四发车

    随着 ToB(企业服务)的兴起和 ToC(消费互联网)产品进入成熟期,线上故障带来的损失越来越大,代码质量越来越重要,而「质量内建」正是 DevOps 核心理念之一. <DevOps 代码质量实 ...

  8. CODING DevOps 代码质量实战系列第一课:代码规范与 Git Flow

    讲师介绍 杨周 CODING DevOps 架构师 CODING 布道师 连续创业者.DIY/Linux 玩家.知乎小 V,曾在创新工场.百度担任后端开发.十余年一线研发和带队经验,经历了 ToB.T ...

  9. CODING DevOps 代码质量实战系列第二课: PHP 版

    讲师介绍 杨周 CODING DevOps 架构师 CODING 布道师 连续创业者.DIY/Linux 玩家.知乎小 V,曾在创新工场.百度担任后端开发.十余年一线研发和带队经验,经历了 ToB.T ...

随机推荐

  1. 图解MySQL索引(二)—为什么使用B+Tree

    失踪人口回归,近期换工作一波三折,耽误了不少时间,从今开始每周更新~ 索引是一种支持快速查询的数据结构,同时索引优化也是后端工程师的必会知识点.各个公司都有所谓的MySQL"军规" ...

  2. 关于同一密码使用generate_password_hash生成不同的密码散列值

    在python的 werkzeug.security 库中有两个函数generate_password_hash与check_password_hash用于对密码明文生成散列值以及检查密码是否与提供的 ...

  3. 重学 Java 设计模式:实战单例模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 5个创建型模式的最后一个 在设计模式中按照不同的处理方式共包含三大类:创建型模式.结 ...

  4. 50个SQL语句(MySQL版) 问题八

    --------------------------表结构-------------------------- student(StuId,StuName,StuAge,StuSex) 学生表 tea ...

  5. Java 第十一届 蓝桥杯 省模拟赛 户户通电(图算法)

    户户通电 题目 问题描述 2015年,全中国实现了户户通电.作为一名电力建设者,小明正在帮助一带一路上的国家通电. 这一次,小明要帮助 n 个村庄通电,其中 1 号村庄正好可以建立一个发电站,所发的电 ...

  6. Java实现 LeetCode 729 我的日程安排表 I(二叉树)

    729. 我的日程安排表 I 实现一个 MyCalendar 类来存放你的日程安排.如果要添加的时间内没有其他安排,则可以存储这个新的日程安排. MyCalendar 有一个 book(int sta ...

  7. Java实现 LeetCode 429 N叉树的层序遍历

    429. N叉树的层序遍历 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右,逐层遍历). 例如,给定一个 3叉树 : 返回其层序遍历: [ [1], [3,2,4], [5,6] ] 说明 ...

  8. Java实现 蓝桥杯VIP 算法训练 大小写判断

    问题描述 给定一个英文字母判断这个字母是大写还是小写. 输入格式 输入只包含一个英文字母c. 输出格式 如果c是大写字母,输出"upper",否则输出"lower&quo ...

  9. Java实现 LeetCode 212 单词搜索 II(二)

    212. 单词搜索 II 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中&quo ...

  10. SQL Server实现 LeetCode 176 第二高的薪水

    176. 第二高的薪水 SQL架构 编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) . +----+--------+ | Id | Salary | +----+- ...