测试 微服务 非常困难。当我第一次深入研究包含七个独立微服务的技术栈时,我才体会到它有多么困难,每个微服务都有自己的代码库、依赖管理、功能分支和数据库模式——而且碰巧还有一组独特的迁移。
真是令人头疼。
我采取的方法是在本地运行所有内容。这意味着每当我想运行端到端测试时,我都需要为七个微服务中的每一个执行以下五个步骤
-
确保我位于正确的代码分支(
master
或feature_xyz
) -
拉取该分支的最新代码
-
确保所有依赖项都是最新的
-
运行任何新的数据库迁移
-
启动服务
这仅仅是运行测试的基线要求。我经常会忘记为一个服务执行其中一个步骤,然后花费 10-15 分钟调试问题。一旦我最终让所有服务都正常运行,我就可以开始启动测试套件。这种经历确实让我怀念起测试一个大型单体应用的时光。
所以,是的,我发现端到端微服务测试非常困难——而且随着你引入的每个新服务,它都会呈指数级增长。但不要害怕,因为有一些方法可以使微服务测试更容易。我与几位 CTO 讨论了他们如何想出自己创造性的方法来解决这个复杂的问题。
测试微服务与测试单体应用
在我们讨论常见的微服务测试方法以及应对这些方法带来的挑战的策略之前,让我们深入探讨一下为什么测试微服务与测试单体应用是不同的概念。
首先,微服务需要额外的步骤,例如管理多个存储库和分支,每个存储库和分支都有自己的数据库模式。但挑战可能比这更深入。
以下是与测试微服务相关的一些关键挑战
-
可用性:由于不同的团队可能管理他们自己的微服务,因此确保微服务的可用性(或者更糟糕的是,试图找到所有微服务都可用的时间)非常困难。
-
碎片化和整体测试:微服务旨在单独工作,并与其他松散耦合的服务协同工作。这意味着开发人员需要隔离测试每个组件,以及将所有组件一起测试。
-
知识差距:特别是在集成测试(我们将在本文后面讨论)中,执行测试的人员需要对每个服务有深入的了解,才能有效地编写测试用例。
尽管存在这些挑战,但微服务的优势太大了,不能因为测试挑战而放弃。可以使用一系列方法来应对微服务测试的挑战。
常见的微服务测试方法
单元测试
微服务在定义上可能更小,但通过单元测试,你可以更加精细。单元测试侧重于可测试软件的最小部分,以确定该组件是否按预期工作。著名的软件工程师、作家和国际演讲家 Martin Fowler 将单元测试分为两类
-
社交型单元测试:这种单元测试方法通过观察模块状态的变化来测试模块的行为。
-
独立型单元测试:这种方法侧重于对象与其依赖项之间的交互和协作,这些依赖项被测试替身取代。
虽然这些单元测试策略是不同的,但 Fowler 提出它们并非相互竞争——它们可以协同使用来解决不同的测试问题。
Pantheon 的 CTO David Strauss 告诉我:“机会在于微服务实际上非常容易进行单元测试。”
Armory 的 CTO Isaac Mosquera 也表示赞同,并补充说 Armory“指导客户专注于单元测试”。
集成测试
通过集成测试,你正在做的事情正如其名称所示:测试组件之间的通信路径和交互,以检测问题。根据 Fowler 的说法,集成测试“通过子系统执行通信路径,以检查每个模块对其对等方交互方式的任何不正确的假设。”
集成测试通常测试微服务与外部服务(例如另一个微服务或数据存储)之间的交互。
Pusher 的平台主管 Pawel Ledwoń 说,他的团队“倾向于集成测试。单元测试对于某些抽象仍然有用,但对于面向用户的功能,它们很难模拟或跳过系统的重要部分。”
Sumo Logic 的首席架构师 Stefan Zier 也透露,他们“在集成测试方面投入了相当大的精力”。
然而,并非我交谈过的每个人都喜欢这个过程。例如,Mosquera 对集成测试主题的看法非常值得注意:“集成测试非常容易出错且成本高昂,就工时而言。投资回报率根本不存在。每个单独的集成测试带来的用例边际覆盖率都很小。
“如果你考虑应用程序的所有代码路径组合,再加上另一个应用程序的代码路径,那么需要编写的测试数量很容易激增到一个无法实现的数字。相反,我们指导客户专注于单元测试覆盖率,以及少量的集成测试,这些测试将演示应用程序关键领域的完全失败,”Mosquera 补充道。
端到端测试
最后但并非最不重要的是端到端测试,正如之前提到的,这可能是一项艰巨的任务。这是因为它涉及测试微服务的每个移动部件,以确保它可以实现你构建它的目标。
Fowler 写道,“端到端测试可能还必须考虑系统中的异步性,无论是在 GUI 中还是由于服务之间的异步后端进程。” 他继续解释说,这些因素如何导致“不稳定性、过长的测试运行时间和额外的测试套件维护成本。”
关于端到端测试,我能给出的最佳建议是限制你为每个服务尝试它的次数。上述其他微服务测试策略(如单元测试和集成测试)之间的健康平衡将帮助你消除较小的问题。端到端测试在定义上更大,需要更多时间,并且更容易出错。为了保持低成本并避免时间浪费,请坚持在所有其他测试方法都已用尽后,以及作为最终的质量保证印章时才进行端到端测试。
初创企业的五种微服务测试策略
测试微服务很困难,但并非不可能。为了应对这些挑战,我从几位 CTO 那里获得了见解,并提炼出他们用来成功处理微服务测试的五种策略。
1. 文档优先策略
SparkPost 的工程副总裁 Chris McFadden 在我们的讨论中很好地总结了文档优先策略
“我们遵循文档优先的方法,因此我们所有的文档都以 Markdown 格式存储在 GitHub 中。我们的 API 文档是开源的,所以都是公开的。然后我们会这样做,在任何人编写任何 API 更改或新的 API 或对 API 的更改之前,他们将首先更新文档,对该更改进行审查以确保其符合我们的 API 约定和标准(所有这些都有文档记录),并确保此处没有引入任何重大更改。确保它也符合我们的命名约定等等。”
如果你愿意更进一步,你可以涉足 API 契约测试,正如之前提到的,这涉及编写和运行测试,以确保微服务的显式和隐式契约按预期工作。
2. 全栈一体化策略
全栈一体化策略需要本地复制云环境,并在一个 vagrant 实例中测试所有内容 ($ vagrant up
)。问题是什么?正如 imgix 的软件工程师 Cindy Sridharan 在一篇博客文章 中解释的那样,这非常棘手
“我在之前工作过的一家公司亲身经历了这种谬误,我们试图在一个 [本地] vagrant box 中启动我们的整个堆栈。你可以想象,这个想法是,一个简单的 vagrant up 应该使公司中的任何工程师(甚至前端和移动开发人员)都能够在他们的笔记本电脑上完整地启动堆栈。”
Sridharan 接着详细介绍了该公司只有两个微服务:一个基于 gevent 的 API 服务器和一些异步 Python 后台工作程序。无论如何,这是一个相对简单的设置。
“我记得我在这家公司的第一周都在试图在本地成功启动 VM,但最终遇到了大量错误。最终,在我第一周的星期五下午 4 点左右,我成功地让 Vagrant 设置工作,并且所有测试都在本地通过了。我记得当时感觉非常疲惫。”她说。
尽管她尽了最大努力记录她遇到的障碍以及她如何克服这些障碍,但 Sridharan 透露,她公司雇用的下一位工程师遇到了他们自己的一系列问题,这些问题无法在另一台笔记本电脑上重现。(我说过这很棘手!)
Sumo Logic 的首席架构师 Stefan Zier 向我解释说,除了难以实现之外,这种本地化测试策略根本无法扩展:“[对于] 本地部署,我们在那里运行大多数服务,因此你得到一个完全运行的系统,而现在即使是 16GB 内存的机器也难以承受。所以这真的无法扩展。”
3. AWS 测试策略
第三种策略涉及为每位工程师启动一个 Amazon Web Services (AWS) 基础设施,以便在其上部署和运行测试。这是一种比上面讨论的全栈一体化策略更具可扩展性的方法。
Zier 称之为“个人部署[策略],这里的每个人都有自己的 AWS 账户。” 他补充说,“你可以在大约十分钟内将笔记本电脑上的代码推送到 AWS 中,并在真正的系统中运行它。”
4. 共享测试实例策略
我喜欢将第四种策略视为全栈一体化和 AWS 测试之间的混合。这是因为它涉及开发人员从他们自己的本地工作站工作,同时利用微服务的单独共享实例来指向他们在测试期间的本地环境。
Scaylr 的工程主管 Steven Czerwinski 解释了这在实践中是如何工作的
“[我们的一些] 开发人员运行一个单独的微服务实例,专门用于测试本地构建。想象一下你是一名开发人员,你在本地工作站上进行开发,并且你没有一种简单的方法来启动图像解析器。但是,你的本地构建器只会指向在 Google 基础设施中运行的测试图像解析器。”
Czerwinski 继续说道,“同样,我们一直在讨论为前端开发人员做这件事。在服务之间隐藏数据库层,这样人们在测试 UI 功能时就不必运行他们自己种类繁多的单体服务器、数据库服务器。他们希望能够依赖一个可以非常频繁更新并且不包含生产或暂存数据或任何类似数据的外部服务器。”
5. 桩服务策略
最后,我们有桩服务测试策略。
Zier 阐述了 Sumo Logic 的桩服务测试方法:“桩服务允许你编写这些微服务的标记或‘桩’,这些桩的行为就好像它们是正确的服务,并且它们在我们的服务发现中宣传自己,就好像它们是真正的服务一样,但它们只是一个虚拟的模仿。”
例如,测试服务可能需要服务意识到用户执行了一组任务。使用桩服务,你可以假装用户(及其任务)已经发生,而无需通常随之而来的复杂性。显然,这种方法比完全运行服务要轻量得多。
帮助你测试微服务的工具
除了这些策略之外,CTO 还建议使用以下工具,他们使用这些工具使微服务测试变得更容易
-
Hoverfly:模拟 API 延迟和故障
-
Vagrant:构建和维护便携式虚拟软件开发环境
-
VCR:单元测试工具
-
Pact:框架消费者驱动的契约测试
-
API Blueprint:设计和原型 API
-
Swagger:设计和原型 API
微服务测试:困难但可行
测试你的微服务不会像在公园散步一样轻松,但额外的工作值得拥有微服务架构的好处。回顾一下,五种策略是
-
文档优先策略
-
全栈一体化策略
-
AWS 测试策略
-
共享测试实例策略
-
桩服务策略
当然,你可能需要调整每个策略以适应你的独特情况,但通过一些传统的试错,你的微服务测试策略应该会形成自己的特色。
[请参阅我们的相关报道,在设计微服务之前你应该知道的 5 条指导原则]
1 条评论