使用从 GitHub Node.js 应用程序运行单元测试 AWS CodeBuild - AWS Prescriptive Guidance

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用从 GitHub Node.js 应用程序运行单元测试 AWS CodeBuild

由托马斯·斯科特 (AWS) 和让-巴蒂斯特·吉洛斯 () 创作 AWS

代码存储库:节点 JS 测试示例

环境:生产

技术:网络和移动应用程序

AWS服务:AWS CodeBuild

Summary

此模式为 Node.js 游戏提供了示例源代码和关键单元测试组件API。它还包括使用 GitHub 存储库运行这些单元测试的说明 AWS CodeBuild,作为持续集成和持续交付 (CI/CD) 工作流程的一部分。

单元测试是一个软件开发过程,在这个过程中,对应用程序的不同部分(称为单元)进行单独和独立的测试,以确保其正确运行。测试验证代码的质量并确认其功能是否符合预期。其他开发人员也可以通过查阅测试轻松熟悉您的代码库。单元测试可缩短未来的重构时间,帮助工程师更快地掌握代码库,并让他们对预期行为充满信心。

单元测试涉及测试单个函数,包括 AWS Lambda 函数。要创建单元测试,您需要一个测试框架和一种验证测试(断言)的方法。此模式中的代码示例使用 Mocha 测试框架和 Chai 断言库。 

有关单元测试和测试组件示例的更多信息,请参阅其他信息部分。

先决条件和限制

  • 具有正确 CodeBuild 权限的活跃AWS账户

  • GitHub 账户(参见注册说明

  • Git(请参阅安装说明

  • 用于进行更改并将代码推送到的代码编辑器 GitHub (例如,您可以使用 AWSCloud9

架构

此模式实施下图中所示的架构。

AWS用于使用和 GitHub 存储库运行单元测试 CodeBuild 的云架构

工具

工具

  • Git ─ Git 是一个可用于代码开发的版本控制系统。

  • AWSCloud9 ─ AWS Cloud9 是一个集成开发环境 (IDE),它支持多种编程语言和运行时调试器以及内置终端,可提供丰富的代码编辑体验。它包含一套工具,可用于对软件进行编码、构建、运行、测试和调试,并帮助您将软件发布到云中。您可以IDE通过网络浏览器访问 AWS Cloud9。

  • AWS CodeBuild─ AWS CodeBuild 是一项完全托管的持续集成服务,它可以编译源代码、运行测试并生成可供部署的软件包。使用 CodeBuild,您无需预置、管理和扩展自己的构建服务器。 CodeBuild 持续扩展并同时处理多个构建,因此您的构建不会在队列中等待。您可以使用预先打包的构建环境快速开始,也可以创建使用您自己的构建工具的自定义构建环境。使用 CodeBuild,按分钟计费所使用的计算资源。

代码

此模式的源代码可在 GitHub示例游戏单元测试应用程序存储库中找到。您可以根据此示例(选项 1)创建自己的 GitHub 存储库,也可以直接使用示例存储库(选项 2)来创建此模式。按照下一节中每个选项的说明操作。选项的选择因用例而定。

操作说明

任务描述所需技能

根据示例项目创建自己的 GitHub 存储库。

  1. 登录到 GitHub。

  2. 创建新存储库。有关说明,请参阅GitHub 文档

  3. 克隆示例存储库并将其推送到您账户中的新存储库中。

应用程序开发者、AWS管理员、AWS DevOps

创建新 CodeBuild 项目。

  1. 登录AWS管理控制台并在 https://console.aws.amazon.com/codesuite/codebuild /hom CodeBuild e 中打开控制台。

  2. 选择 Create build project(创建构建项目)

  3. 在 “项目配置” 部分,在 “项目名称” 中键入 aws-tests-sample-node-js

  4. 在 “来源” 部分中,对于源提供商,选择GitHub

  5. 对于 “存储库”,在我的 GitHub 账户中选择 “存储库”,然后将其粘贴URL到您新创建的 GitHub 存储库中。

  6. 主要源 Webhook 事件中, 选择每次将代码更改推送到此存储库时都会重新生成 

  7. 对于事件类型,选择PUSH。 

  8. 在 “环境” 部分中,选择托管映像、Amazon Linux 和最新映像。

  9. 所有其他选项保留默认设置,然后选择创建构建项目

应用程序开发者、AWS管理员、AWS DevOps

开始构建。

审核页面上,选择开始构建以运行构建。

应用程序开发者、AWS管理员、AWS DevOps
任务描述所需技能

创建新的 CodeBuild 构建项目。

  1. 登录AWS管理控制台并在 https://console.aws.amazon.com/codesuite/codebuild /hom CodeBuild e 中打开控制台。

  2. 选择 Create build project(创建构建项目)

  3. 在 “项目配置” 部分,在 “项目名称” 中键入 aws-tests-sample-node-js

  4. 在 “来源” 部分中,对于源提供商,选择GitHub

  5. 对于 “存储库”,选择 “公共存储库”,然后粘贴URL:https://github.com/aws-samples/node-js-tests-sample

  6. 在 “环境” 部分中,选择托管映像、Amazon Linux 和最新映像。

  7. 所有其他选项保留默认设置,然后选择创建构建项目

应用程序开发者、AWS管理员、AWS DevOps

开始构建。

审核页面上,选择开始构建以运行构建。

应用程序开发者、AWS管理员、AWS DevOps
任务描述所需技能

查看测试结果。

在 CodeBuild 控制台中,查看 CodeBuild 作业的单元测试结果。这些结果应与其他信息部分中显示的结果相符。

这些结果验证了 GitHub 存储库与的集成 CodeBuild。 

应用程序开发者、AWS管理员、AWS DevOps

应用 Webhook。

现在,您可以应用 Webhook,这样无论何时将代码变更推送到存储库的主分支,都可以自动启动构建。有关说明,请参阅CodeBuild 文档

应用程序开发者、AWS管理员、AWS DevOps

相关资源

其他信息

单元测试结果

在 CodeBuild 控制台中,项目成功生成后,您应该会看到以下测试结果。 

单元测试的预期结果

单元测试组件示例

本节介绍单元测试中使用的四种类型的测试组件:断言、间谍、存根和模拟。它包括每个组件的简要说明和代码示例。 

断言

断言用于验证预期结果。这是一个重要的测试组件,因为它可以验证给定函数的预期响应。以下示例断言验证了初始化新游戏时返回的 ID 是否介于 0 和 1000 之间。

const { expect } = require('chai'); const { Game } = require('../src/index'); describe('Game Function Group', () => { it('Check that the Game ID is between 0 and 1000', function() { const game = new Game(); expect(game.id).is.above(0).but.below(1000) }); });

间谍

间谍用于观察函数运行时发生的情况。例如,您可能希望验证函数的调用是否正确。以下示例显示了在游戏类对象上调用启动和停止方法。

const { expect } = require('chai'); const { spy } = require('sinon'); const { Game } = require('../src/index'); describe('Game Function Group', () => { it('should verify that the correct function is called', () => { const spyStart = spy(Game.prototype, "start"); const spyStop = spy(Game.prototype, "stop"); const game = new Game(); game.start(); game.stop(); expect(spyStart.called).to.be.true expect(spyStop.called).to.be.true }); });

存根

存根用于覆盖函数的默认响应。当函数发出外部请求时,这特别有用,因为您想避免从单元测试中发出外部请求。(外部请求更适合集成测试,集成测试可以对不同组件之间的请求进行物理测试。) 在以下示例中,存根强制使用getId函数的返回 ID。

const { expect } = require('chai'); const {.stub } = require('sinon'); const { Game } = require('../src/index'); describe('Game Function Group', () => { it('Check that the Game ID is between 0 and 1000', function() { let generateIdStub = stub(Game.prototype, 'getId').returns(999999); const game = new Game(); expect(game.getId).is.equal(999999); generateIdStub.restore(); }); });

模拟

模拟是一种虚假的方法,具有用于测试不同场景的预编程行为。模拟可以被视为存根的扩展形式,可以同时执行多个任务。在以下示例中,使用模拟来验证三个场景:

  • 调用函数 

  • 使用参数调用函数

  • 函数返回整数 9

const { expect } = require('chai'); const {.mock } = require('sinon'); const { Game } = require('../src/index'); describe('Game Function Group', () => { it('Check that the Game ID is between 0 and 1000', function() { let mock = mock(Game.prototype).expects('getId').withArgs().returns(9); const game = new Game(); const id = get.getId(); mock.verify(); expect(id).is.equal(9); }); });