如何测试我的无服务(Serverless)应用?

本文翻译自:medium.com/free-code-ca

无服务(Serverless)不单单是一个云计算的执行模型,它改变了我们设计、构建和部署应用的方式,它同样改变了我们测试我们应用的方式。

Alex 是一名普通的 JavaScript 开发者,最近主要聚焦在 Node.js。

This is Alex

在这几个月里,他的好朋友 Anna 和 Jeff 总是在谈论着 serverless 相关的话题,尽管这些应用程序有时候很烦人,但是他很喜欢无服务应用的想法,他甚至在 AWS Lambda 和 Azure 上部署了一些简单的函数。

Anna and Jeff are always talking about that serverless thingy


有一次,Alex 和他的团队有一个新项目,经过一系列的分析后,Alex 认为这个项目非常适合 Serverless,他向团队的小伙伴们提出了这个想法,有一些人很兴奋,有一个小伙伴不喜欢,但是大多数人都没有一个很强烈的建议该怎么弄,所以他们决定试一试,这个项目不大,风险也很低。

Alex’s team discussing using serverless on their new project


团队阅读了关于 serverless 的内容,并想到了如何构建这个新的应用程序,但是没有人能确定应该如何将 serverless 融入到他们共同开发的过程中。

此时,他们的过程是这样的:

  1. 分析这个应用程序的特性
  2. 对于不太复杂的特性,他们开始编码,然后在本地运行并进行一些测试
  3. 对于更复杂的特性,他们使用测试驱动开发(TDD)的方式:他们从测试开始,然后编写代码,并在本地进行测试
  4. 当特性编码完成后,他们使用 CI 工具将其部署到测试环境中
  5. 然后 QA 团队对这个新特性进行手动测试,如果一切顺利,该应用程序将通过 CI 投入生产
Alex’s team’s common development process


他们决定开始一步一步的走,当遇到问题的时候在一起去解决问题。

他们选择了一个小的特性,因为它很简单,当编码完成时,他们遇到了第一个难题,如何在本地运行无服务应用呢?


本地测试

对于 Serverless 应用,不需要管理基础设施,这听起来不错,但是如何在本地运行应用程序呢?

First roadblock: how do you run serverless application locally?

根据应用程序和 serverless vendor,可以在本地运行应用程序的某些部分,可以使用以下工具和技术:


当然,上述只是列出来了一部分,还有更多的工具,而且几乎每天都有新的工具出现。

这些工具大部分都有一定的局限性,它可以模拟 Serverless 函数和一些其他服务,比如 API 网关,但是像权限管理、认证层和其他服务呢?

本地测试有助于快速验证,以确保应用的功能可以正常工作,但是有没有更好的办法来确保 Serverless 应用可以按照预期来运行呢?答案是有的,第一步也是最重要的一步是:编写测试。

所以 Alex 和他的团队尝试了在本地运行第一个函数后,似乎看起来是有效的,然后他们进入了下一步。


自动化测试

Alex 和他的团队刚刚切换到 Jest 来测试他们的 Node.js 程序,他们仍然要做大量的前端工作,所以他们希望能在任何可能的情况下对整个开发栈使用同一个工具。他们也可以使用 Jest 测试 Serverless 应用吗?他们应该测试什么?

Second roadblock: how does serverless affect automated testing?


经过快速的调研,他们意识到可以使用他们最喜欢的 Node.js 测试工具,Jest、Jasmin、Mocha 等在 Serverless 的情况下运行的很好。

在 Serverless 应用中应该测试什么呢?

在 Node.js 程序中,Alex 和他的团队遵循三层测试自动化金字塔,Mike Cohn 在他的《Succeeding with Agile》书中首次提到了测试金字塔。

正如测试金字塔所定义的,他们有:

  • 很多单元测试,因为它们是编写和运行最快的
  • 更少的集成测试,因为成本很高,并且需要更多的时间来运行
  • 一些 UI 测试,因为它们是成本最高的(需要一些 GUI 工具)和运行最慢的


除此之外,它们还有基于 session 的手动测试,这些由 QA 团队完成。

test pyramid with manual testing


Serverless 会如何影响到测试自动化金字塔呢?

答案取决于层次。但是测试金字塔看起来不太像埃及金字塔(Egyptian pyramids),而更像玛雅金字塔(Mayan pyramids)。

单元测试层受影响不大,单元测试仍然是编写和运行成本最低的,但是单元可以更小。

集成测试层变得更加重要,因为 Serverless 应用严重依赖于集成。它的成本更低一些,因为只用于测试的 Serverless 数据库成本是很低的。因此,在一个 Serverless 的“测试金字塔”中,需要有更多的集成测试。

GUI 测试层成本也更低、更快,因为并行化更便宜。

手动测试层保持不变,但是 serverless 可以帮助您稍微改进它,我们稍后将对此进行详细讨论。

Serverless “test pyramid”


Alex 和他的团队终于知道了该关注哪些点。下一个问题是如何编写一个更加容易进行测试的函数。

如何编写可测试的 Serverless Functions?

在编写 Serverless Functions 时,需要考虑以下风险:

  • 配置风险:数据库和表的配置是否正确?或者,您有访问权限吗?
  • 技术流程风险:您是否按照正确的方式来解析和使用收到的请求? 或者,您是否有正确地处理成功响应和异常?
  • 业务逻辑风险:您是否遵循了应用程序中所有的业务逻辑规则?
  • 集成风险:您是否正确读取了收到的请求结构?是否将订单正确地存储到数据库中?

为了确认您的 Serverless 函数正常工作,您需要测试所有这些风险。

可以像在集成测试中那样测试每一个,但是,每次您想要测试这些风险之一时设置和配置服务并不是最优的。正如 Aleksandar Simovic 喜欢说的:

Imagine if testing automobiles was done that way. That would mean that every time you wanted to test a single screw or even a mirror in a car, you would have to assemble and then disassemble the whole car.


为了让这个应用程序更加可测试,一个清晰的解决方案是将函数分解成几个更小的函数。

其中一个很好的方法是将六角架构(Hexagonal Architecture)应用于 Serverless 函数。

Hexagonal Architecture,或端口和适配器,是一种应用程序架构,它通过责任层促进关注点的分离。它的提出者 Alistair Cockburn 解释道:

Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.


那么,如何将其应用于 Serverless 函数呢?

由于 Alex 和他的团队使用 AWS,他们最终得到了如下结构:

  • 函数业务逻辑暴露很少的“端口”(或很少的参数)。例如,一个用于传入事件,一个用于持久化存储,一个用于通知。
  • 他们有两个适配器用于触发函数的事件,一个用于真正的 AWS Lambda 触发器,另一个用于本地测试。
  • 他们有几个适配器用于持久化存储和通知。例如,DynamoDB 表适配器和内存适配器。
Hexagonal architecture of AWS Lambda function

Alex 和他的团队很高兴他们取得了进展。但在我们继续之前,让我们看看 Hexagonal Architecture 如何影响测试金字塔的每一层。


单元测试

单元测试保持不变,但是由于 Hexagonal Architecture,编写单元测试更容易,它们可以简单地使用本地适配器或模拟作为适配器来独立地测试功能业务层。

集成测试

集成测试从 Hexagonal Architecture 中获益良多,他们能够完全测试应用,并使用其他适配器模拟第三方集成。

这在实践中是如何运作的呢?

它们的每个 Serverless 函数都有 lambda.js 和 main.js 文件。main.js 中包含 serverless 函数的业务逻辑,而 lambda.js 负责连接适配器并调用 main.js。

main.js 有自己的单元和集成测试,但是它的集成测试并不测试所有集成进的终端程序,例如 AWS S3,因为这会降低进度。相反,它们使用内存适配器来测试具有存储功能集成的函数。

AWS S3 集成是通过 FileRepository 完成的,它有自己的单元和集成测试,集成测试使用 AWS S3 来确保最终集成的运行。

与 main.js 相反,lambda.js 没有测试,因为大多数时候它只有几行代码。

Visual representation of single AWS Lambda function with tests

这种方法类似 MindMup 团队用于测试 Serverless 功能的技术。它可以轻松地测试函数的集成,并且仍然可以保持快速测试。

GUI测试

由于 Alex 和他的团队正在为应用构建一个后端,GUI 测试层并不相关。但是随着他们对 serverless 的了解越来越多,他们意识到可以使用它来改进他们正在开发的其他应用程序的 GUI 测试。

UI 测试成本很高并且速度慢,因为它们在浏览器中运行。但是,serverless 的成本很低,而且它的伸缩性很快。

如果他们能用 AWS Lambda 运行浏览器,则可以获得廉价的并行化,这将使他们的 UI 测试更便宜、更快。

但是,你能在 serverless 的函数中运行浏览器吗,比如 Chrome ?

答案是可以的!在 Serverless ChromeChromeless, 和 Puppeteer.等工具的帮助下,这是很容易的。

Using AWS Lambda functions for parallelization of UI tests


Serverless 和 headless 浏览器的结合可以为我们带来新一代的 UI 测试工具,比如 Appraise


CI / CD

由于 Alex 和他的团队测试了他们的第一个 serverless 函数,是时候将代码部署到测试环境中了。这就遇到了一个新的问题:他们如何使用 CI/CD 工具来部署他们的无服务器应用?


答案很简单:他们可以使用 CI 工具运行测试并部署应用。要部署应用程序,可以使用任何流行的工具,比如 Claudia.jsAWS SAMServerless Framework.

您仍然可以使用喜欢的CI工具(如 JenkinsTravisCISemaphoreCI),或者如果想继续使用AWS,可以尝试 AWS CodeBuild


手工测试

即使手动测试没有直接受到 serverless 的影响,团队也找到了改进 QA 流程的方法。

Serverless 应用程序的部署很便宜,而且安装起来往往很快。此外,如果没有人使用这个应用程序,你就不用为它付费。这意味着拥有一个测试环境从来没有这么便宜过!

此外,使用 serverless,可以将功能从一个阶段提升到另一个阶段,这意味着 QA 团队可以测试一个功能,当确认该功能有效时,可以将相同的功能推广到生产中。

除了测试

Alex 和他的团队将他们的第一个无服务器功能发布到预生产中,团队很高兴他们学会了如何测试无服务器应用程序。


他们继续在项目上使用 serverless,并将其引入到其他项目中。Alex 加入了他的朋友 Anna 和 Jeff 的行列,从此他们幸福地生活在一起。

Serverless preachers crew got a new member

后记

但即使他们的应用程序经过了良好的测试,一夜之间还是发生了一些事情。

经过调查,他们发现其中一个集成发生了变化,虽然他们知道测试对于 Serverless 程序很重要,但这还不够。

由于 Serverless 应用程序严重依赖于集成,风险从代码转移到集成。而且,为了能够捕捉集成变化并快速做出反应,应用程序需要适当的监控。

幸运的是,市场上每天都有越来越多的 Serverless 监控工具,一些好的和流行的选择是 IOpipeThundraDashbirdEpsagon

但是,Serverless 应用通常有一个厚客户端,这意味着后端监视是不够的,需要为前端使用类似的工具,目前也有很多不错的工具,如 SentryRollbar

但本着 Serverless 的精神,这个文章的作者创建了一个名为 Desole 的开源错误跟踪程序,这是一个无服务器程序,可以安装在 AWS 帐户。它使组织能够跟踪应用程序异常和错误,而不必在 SaaS 的便利性和自托管解决方案的安全性之间做出选择。您可以在这里查看:https://desole.io

发布于 2019-09-01

文章被以下专栏收录