如何编写 Serverless 应用的测试

该内容并非本站原创,只因原内容字体太小、排版较乱,学习不便,故重新整理发布,如有侵权请联系删除[yestool666#gmial.com] 同时可点击底部github移步出处

如 Serverless Framework 官方所说

虽然 Serverless 架构在服务业务逻辑方面引入了很多简单性,但是它的一些特性给测试带来了挑战。他们是:

  • Serverless 架构是独立的分布式服务的集成,它们必须被独立地和一起地测试。
  • Serverless 架构依赖于互联网、云服务,这些服务很难在本地模拟。
  • Serverless 架构可以具有事件驱动的异步工作流程,这些工作流程很难完全仿真。

因此官方建议:

  • 编写您的业务逻辑,使其与 FaaS 提供商(例如,AWS Lambda)分开,以保持提供者独立性,可重用性和更易于测试。
  • 当您的业务逻辑与FaaS提供商分开编写时,您可以编写传统的单元测试以确保其正常工作。
  • 编写集成测试以验证与其他服务的集成是否正常工作。

Serverless 应用的测试

在传统的测试金字塔里,我们会写更多的单元测试,并尽可能地尽少集成测试。同样的,在 Serverless 架构应用里,我们会写同样数量的单元测试,只是会写更多地集成测试,用于测试与服务间的集成。而这些测试,往往更加依赖于网络,并且这些测试越需要我们隔离架构层级。

因而,这种情况下,我们需要在测试上花费更多的精力。

对于单元测试来说,在之前的 Express 示例里,我们做了一个不错的 Demo。我们隔离了 Express 与 Lambda 函数之间的代码,只需要再加上一个本地的 Express 环境,那么我们就可以直接在本地运行了。而借助于上一篇中提供的 serverless-offline,我们则可以隔离本地数据库。

随后,我们需要将 Serverless 应用部署测试环境。然后运行我们的测试脚本,自动地打开浏览器,进行操作。然后验证数据库中的数据是否是正确的,而一些都依赖于网络来执行。这就意味着,我们仿佛在不断地对接第三方系统,看上去就像一场场的恶梦。好在,我们也可以在 AWS 上运行测试,至少会让网络问题变得好一些。

步骤

在这里,我们要用 serverless-mocha-plugin 插件,这是一个基于 Mocha 框架、用于为 Serverless Framework 的添加测试的插件。

它的 Setup 过程非常简单,先添加插件:

yarn add --dev serverless-mocha-plugin

随后,添加到 serverless.yml 文件中:

plugins:
  - serverless-mocha-plugin

接着,我们就可以创建测试了。

创建测试

除了运行测试,它还提供创建测试的命令。只需要运行命令

sls create test -f functionName

如,在这里我们是这样的:

$ sls create test -f hello

Serverless: serverless-mocha-plugin: created test/hello.js

其文件的内容如下:

'use strict';

// tests for hello
// Generated by serverless-mocha-plugin

const mochaPlugin = require('serverless-mocha-plugin');
const expect = mochaPlugin.chai.expect;
let wrapped = mochaPlugin.getWrapper('hello', '/handler.js', 'hello');

describe('hello', () => {
  before((done) => {
    done();
  });

  it('implement tests here', () => {
    return wrapped.run({}).then((response) => {
      expect(response).to.not.be.empty;
    });
  });
});

如果你写过 Mocha 测试的话,那么你应该能看懂上面的代码。

运行测试

现在,我们就可以运行测试了,命令以以下的格式运行:

sls invoke test [--stage stage] [--region region] [-f function1] [-f function2] [...]

我们也可以直接运行所有的测试:

$ sls invoke test


  hello
    ✓ implement tests here


  1 passing (7ms)

更准确的测试

让我们再让测试有针对性一点。在 handler.js 中,我们返回的 body 是一个字符串:

const response = {
  statusCode: 200,
  body: JSON.stringify({
    message: 'Go Serverless v1.0! Your function executed successfully!',
    input: event,
  }),
};

那么,我们就应该去测试一下相应的字符串:

it('implement tests here', () => {
  return wrapped.run({}).then((response) => {
    let body = JSON.parse(response.body);
    expect(body.message).equal('Go Serverless v1.0! Your function executed successfully!');
  });
});

结论

总的来说,对于普通的单元测试来说,和一般的测试差不多。对于数据库操作什么相关的函数来说,这就是一件复杂的事。