如何使用Github Actions运行MySQL测试用例?| StoneDB技术分享会#7

2023/10/26 18:15
阅读数 22

StoneDB开源地址

https://github.com/stoneatom/stonedb

编辑: 桑榆
责编:宇亭

作者:斯科特-斯特罗兹

MySQL 开发者布道师

最近我正在研究与 MySQL 数据库交互的 Node.js 代码编写和运行测试的方法。本文将介绍使用第三方(如 Test Containers)在干净的数据库中运行测试的方法,以及如何使用 Knex 管理数据库更改。今天,我们将讨论当代码被推送到仓库时,如何使用GitHub Actions自动化运行这些测试。

当前问题

开发人员在修改代码之前,应该进行编写、更新和运行测试以确保代码的质量。但有时我们会忽略这些测试流程,直接进行快速修复错误的操作,这可能导致忽略测试的情况发生。由于我们自身的原因,有时候可能会出现不必要的停机时间,因为未经充分测试的代码被引入生产环境中,会造成严重破坏。因此,为了避免这种情况,我们可以编写全面的测试来验证代码是否按照预期运行。

解决方案

运行测试应该是任何持续集成(CI)或持续部署(CD)工作流程的一部分。我们可以使用 GitHub Actions 来管理这一过程。GitHub Actions 允许我们在版本库发生变化时(如推送到版本库、创建拉取请求、提交问题等),自动构建、测试和部署代码的工作流程。

获取代码
要获取本演示中的代码,前往该 GitHub repo 中复制并粘贴。这段代码来自我们在本文中讨论过的演示。我把其移至一个单独的 repo 中,方便我在开发不同的演示时运行这些测试。
通过 SSH 从命令行复制 repo 的命令:
git clone git@github.com:boyzoid/github_actions_testcontainers.git
接下来,更改此演示的目录:
cd github_actions_testcontainers
最后,如果你想在本地运行测试,请运行以下命令:
npm install
完成这些步骤后,目录结构应如下图所示:
代码概述

在这篇文章中,不再赘述 Node.js 代码的细节和测试的结构。可以查看上一篇文章中的代码概述进行深入分析。

本文将主要谈谈本代码的不同之处。 特别是 .github/workflows/node.test.yml 文件。

定义工作流


使用 GitHub Actions 时,我们通过创建名为 .github/workflows/file_name.yml 的文件夹来定义工作流。在本例中,文件名为 node.test.yml。在一个项目中可以有多个工作流,每个工作流在触发不同事件时执行不同的操作。

下面是我们的工作流程,将逐节分解。
name: Node.js Testson:  push:    branches: [ "main"]jobs:  build:    runs-on: ubuntu-latest    strategy:      matrix:        node-version: [20.x]    steps:    - uses: actions/checkout@v3    - name: Use Node.js $      uses: actions/setup-node@v3      with:        node-version: $        cache: 'npm'    - run: npm ci    - run: npm test
  • name
“name” 属性很容易理解。它是我们工作流程的名称。
  • on
属性“on ”定义了触发工作流执行的操作。在这里,使用 “push” 和子属性 ["main"] 来表示我们希望在将代码推送到名为 “main” 的分支时执行该工作流。需要注意的是,分支值是一个数组,因此我们可以在此值中添加其他分支。
  • jobs
接下来,我们使用“ jobs” 属性来定义工作流处理时要执行的任务。在这里,我们有一个名为“build”的单个作业。
  • runs-on
“Runs-on” 属性定义了运行作业的机器类型。我们使用的是 GitHub 托管上的运行程序和最新版本的 Ubuntu。
  • strategy. matrix
使用 “strategy.matrix 属性”,我们在单个作业中设置变量,并根据这些变量的组合创建多个作业运行。还可以使用矩阵功能,在不同的语言或操作系统版本上测试我们的代码。在本例中,我们使用 20.x 版本的 Node.js 进行测试。
  • 步骤

接下来是步骤属性,我们希望在工作中执行的进程列表。其中一些步骤使用通过 GitHub Actions 提供的预定义操作。

  1. 首先,使用名为 "checkout "的预定义操作。将代码从 GitHub 签出到运行程序。在本例中,它签出的是主分支。

  2. 接下来是使用 Node.js 的步骤,同样使用了预定义的动作。该操作名为 actions/setup-node@v3。该操作使用 strategy.matrix 中的值来设置指定版本的 Node。

  3. 然后运行 npm ci 命令,安装 package.json 文件中定义的所有依赖项。

  4. 最后运行 npm test 命令进行测试。


启用工作流

启用工作流的方法都很简单。只需提交 YAML 文件,并将更改推送到 GitHub 上的远程仓库。GitHub 就会接管这些更改。


运行工作流

当仓库的主分支检查代码时,我们的工作流会开始运行。可以在 GitHub 的 “action”选项卡上查看工作流的进度或历史记录。



在 “action”页面,我们能看到已运行的所有工作流的列表。可以看到代码推送时使用的提交信息、(2)工作流名称、(3)提交 ID和(4)提交代码的人员。



点击“ commit message ”提交信息,可以看到运行的详细信息。即(1)状态 、(2)运行时间 以及(3)工作流本身的详细信息。



我们点击 “ 1 job completed " 链接,能看到已完成任务的列表。在本例子中,将看到一个名为 "biild  20.x “的作业。点击“build 20.x ”链接后,可以看到工作流的详细信息。



该视图列出了运行工作流时的所有操作,包括设置和分解运行程序。由于我们关注的是测试是否成功运行,因此应重点关注运行 npm 测试的详细信息。


> github_actions_testcontainers@1.0.0 test> node --test
TAP version 13# Subtest: Testing Application # Subtest: Container should be running ok 1 - Container should be running --- duration_ms: 89265.867539 ... # Subtest: Testing Migration # Subtest: User table exists ok 1 - User table exists --- duration_ms: 7.070651 ... # Subtest: User Type table exists ok 2 - User Type table exists --- duration_ms: 4.415232 ... 1..2 ok 2 - Testing Migration --- duration_ms: 12.363089 ... # Subtest: Testing Seed # Subtest: User data exists ok 1 - User data exists --- duration_ms: 15.890114 ... # Subtest: User Type data exists ok 2 - User Type data exists --- duration_ms: 25.731585 ... 1..2 ok 3 - Testing Seed --- duration_ms: 42.748207 ... # Subtest: Testing User Repo # Subtest: Can add user ok 1 - Can add user --- duration_ms: 23.006665 ... 1..1 ok 4 - Testing User Repo --- duration_ms: 24.088673 ... 1..4ok 1 - Testing Application --- duration_ms: 89618.999211 ...1..1# tests 10# suites 0# pass 10# fail 0# cancelled 0# skipped 0# todo 0# duration_ms 90219.293716


上述信息显示了运行每个测试的单独输出,最后还有一个摘要。可以看到运行了 10 个测试,并且全部通过。如果有测试失败,将在 "action "选项卡中看到相关提示,并发送一封电子邮件。

下面是 GitHub 网页界面中的详细信息。



点击查看工作详情后,将看到以下内容:

> github_actions_testcontainers@1.0.0 test> node --test
TAP version 13# Subtest: Testing Application # Subtest: Container should be running ok 1 - Container should be running --- duration_ms: 24339.372971 ... # Subtest: Testing Migration # Subtest: User table exists ok 1 - User table exists --- duration_ms: 4.348173 ... # Subtest: User Type table exists ok 2 - User Type table exists --- duration_ms: 2.615384 ... 1..2 ok 2 - Testing Migration --- duration_ms: 7.682252 ... # Subtest: Testing Seed # Subtest: User data exists ok 1 - User data exists --- duration_ms: 5.204167 ... # Subtest: User Type data exists ok 2 - User Type data exists --- duration_ms: 8.624846 ... 1..2 ok 3 - Testing Seed --- duration_ms: 14.590808 ... # Subtest: Testing User Repo # Subtest: Can add user not ok 1 - Can add user --- duration_ms: 12.525421 location: 'file:///home/runner/work/github_actions_testcontainers/github_actions_testcontainers/test/knex-demo.test.js:63:17' failureType: 'testCodeFailure' error: |- Expected values to be strictly equal:
3 !== 4
code: 'ERR_ASSERTION' name: 'AssertionError' expected: 4 actual: 3 operator: 'strictEqual' stack: |- TestContext.<anonymous> (file:///home/runner/work/github_actions_testcontainers/github_actions_testcontainers/test/knex-demo.test.js:74:20) process.processTicksAndRejections (node:internal/process/task_queues:95:5) async Test.run (node:internal/test_runner/test:632:9) async TestContext.<anonymous> (file:///home/runner/work/github_actions_testcontainers/github_actions_testcontainers/test/knex-demo.test.js:63:9) async Test.run (node:internal/test_runner/test:632:9) async TestContext.<anonymous> (file:///home/runner/work/github_actions_testcontainers/github_actions_testcontainers/test/knex-demo.test.js:58:5) async Test.run (node:internal/test_runner/test:632:9) async startSubtest (node:internal/test_runner/harness:208:3) ... 1..1 not ok 4 - Testing User Repo --- duration_ms: 13.361816 location: 'file:///home/runner/work/github_actions_testcontainers/github_actions_testcontainers/test/knex-demo.test.js:58:13' failureType: 'subtestsFailed' error: '1 subtest failed' code: 'ERR_TEST_FAILURE' stack: |- async TestContext.<anonymous> (file:///home/runner/work/github_actions_testcontainers/github_actions_testcontainers/test/knex-demo.test.js:58:5) ... 1..4not ok 1 - Testing Application --- duration_ms: 24628.972343 location: 'file:///home/runner/work/github_actions_testcontainers/github_actions_testcontainers/test/knex-demo.test.js:8:1' failureType: 'subtestsFailed' error: '1 subtest failed' code: 'ERR_TEST_FAILURE' ...1..1# tests 10# suites 0# pass 7# fail 3# cancelled 0# skipped 0# todo 0# duration_ms 25010.234841Error: Process completed with exit code 1.


本文提供了10次测试运行的结果,其中7 次通过,3 次失败。


如果您一直关注本系列,应该记得我们在测试中使用 Testcontainers 作为 MySQL 数据库的源代码。你可能已经注意到,我们在代码或 YAML 文件中没有涉及这一点。这是因为GitHub 托管的运行程序默认已经运行了 Docker,因此我们不需要采取任何特殊步骤来使测试正常运行。


总结


CI/CD 工作流允许自动化代码构建和部署。其中包括运行测试以验证代码是否按预期运行。借助 GitHub 操作,我们不仅可以建立构建和部署的工作流,还可以运行测试。通过 GitHub 操作,每次代码推送到仓库时都可以使用相同的流程和命令来运行测试。



 

作者:斯科特-斯特罗兹

MySQL 开发者布道师

Scott 是一位拥有 20 多年多种语言开发经验的开发人员。这些年来,唯一不变的是他的开发中一直有MySQL。他热衷于分享自己在编码过程中学到的东西,以便其他人学习。




StoneDB 介绍
StoneDB 是石原子科技自主设计研发的国内首款完全兼容于 MySQL 生态的开源 一体化实时 HTAP 数据库产品,具备行列混存、智能索引等核心特性,为 MySQL 数据库提供在线数据实时就近分析服务,能够高效解决 MySQL 数据库在分析型应用场景中面临的能力问题。同时,StoneDB 使用多存储引擎架构的设计,事务引擎具有数据强一致特性,具备完整的事务并发处理能力,使得 StoneDB 可以替代 MySQL 数据库满足在线事务处理场景的需求,使用 MySQL 的用户,通过 StoneDB 可以实现 TP+AP 混合负载,分析性能提升 10 倍以上,不需要进行数据迁移,也无需与其他 AP 集成,弥补 MySQL 分析领域的空白。

加入StoneDB社区
Github:https://github.com/stoneatom/stonedb
Gitee:https://gitee.com/StoneDB/stonedb
社区官网:https://stonedb.io/
哔哩哔哩:https://space.bilibili.com/1154290084
Twitter:https://twitter.com/StoneDataBase
Linkedin:https://www.linkedin.com/in/stonedb/

加入微信群:添加社区助理-小石侠;加入钉钉群:扫描下方钉钉群二维码。




本文分享自微信公众号 - StoneDB(StoneDB2021)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部