GitLab CI 并行执行 Cypress 测试脚本

文章目录

  • 1. 目前流行的并行运行方法
    • 1.1 官方 parallel 参数
    • 1.2 个人开发者写的插件
    • 1.3 基于 CI 平台的
  • 2. GitLab CI Parallel
    • 2.1 介绍
    • 2.2 使用方法
  • 3. 根据 CI_NODE_INDEX 生成测试目录
    • 3.1 切分用例的不同方向
    • 3.2 实现效果
    • 3.3 源码
  • 4. gitlab-ci.yaml 中的改动
    • 4.1 由js脚本来生成测试目录
  • 5. 效果如何?
    • 5.1 耗时变小了
    • 5.2 retry 成本变低了

随着用例越来越多,Cypress 脚本执行效率已经越来越慢了。我们尝试减少运行时间的过程中,做了一些事情。今天来分享一下。

1. 目前流行的并行运行方法

1.1 官方 parallel 参数

· 这种方法需要基于record参数,需要使用官方的云服务[链接]

1.2 个人开发者写的插件

· 这里不列举了,我尝试过了2~3个,都不太好用。

1.3 基于 CI 平台的

· 本文着重讲这个方法,参考了这位大佬的文章 [链接]

2. GitLab CI Parallel

2.1 介绍

GitLab CI 提供一种在Pipline中可以并行执行Job的方法
就是 parallel参数 [官方文档]

# gitlab-ci.yaml
test:
  stage: test
  parallel: 5
  script:
    - yarn cypress run --spec "./**/*.spec.js" 

配置后,效果如图
GitLab CI 并行执行 Cypress 测试脚本_第1张图片

2.2 使用方法

如果只是单纯的在 gitlab-ci.yaml 文件中加上 parallel: 5,只会让你的测试重复跑5遍,这显然不是我们想要的效果。

那么如何能5个并行任务执行不同的测试用例呢?

官方文档中指出,提供了2个参数,CI_NODE_INDEX 和 CI_NODE_TOTAL,分别是当前下标 与 总数量。

那么我们通过编写一个脚本,根据一定规则来切分用例为5份。然后运行cypress时,指定spec参数为不同的测试目录,是不是就可以实现了呢?

3. 根据 CI_NODE_INDEX 生成测试目录

3.1 切分用例的不同方向

前文提到的 大佬 的想法是,获取所有.spec.js文件,再均匀分配给所有并行job,分组对象是用例。
好处是执行时间更平均,但是业务结构被破坏了,个人更倾向于,按用例文件夹来分组,也就是分组对象是第一层文件夹(模块)。

大家可以参考我的脚本,也可以参考大佬的切分方法。其中我增加了 -b 参数来接收业务,再指定目录的逻辑,是基于业务,可以忽略。

3.2 实现效果

例如 /integration 目录下有10个文件夹,当前 CI_NODE_INDEX 是 1,CI_NODE_TOTAL 是 3的情况下,会返回 1,4,7,10 这4个目录。

3.3 源码

./scripts/cypress-parallel.js

const fs = require('fs')
const path = require('path')
const NODE_INDEX = Number(process.env.CI_NODE_INDEX || 1)
const NODE_TOTAL = Number(process.env.CI_NODE_TOTAL || 1)
var TEST_FOLDER = './cypress/integration'
var program = require('commander')

program.version('1.0.0').option('-b, --business_line [value]', '业务线', '').parse(process.argv)

/**
 * 输出测试目录列表
 */
console.log(getSpecDirs().join(','))

/**
 * 获取当前需要运行的测试目录
 */
function getSpecDirs () {
  if (program.business_line.toUpperCase() === 'C') {
    TEST_FOLDER += /c'
  } else if (program.business_line.toUpperCase() === 'B') {
    TEST_FOLDER += '/b'
  }
  const allSpecFiles = walk(TEST_FOLDER)
  return allSpecFiles.sort().filter((_, index) => index % NODE_TOTAL === NODE_INDEX - 1)
}

/**
 * 生成指定目录下所有可测试目录
 * @param {string} dir 目录地址
 */
function walk (dir) {
  const files = fs.readdirSync(dir)

  var specDirs = []
  var hasFile = false
  files.forEach((file) => {
    const filePath = path.join(dir, file)
    const stats = fs.statSync(filePath)
    if (stats.isDirectory() && ['pages'].indexOf(file)) {
      specDirs.push(filePath + '/**/*.spec.js')
    } else if (stats.isFile() && !hasFile && file.indexOf('spec.js') !== -1) {
      specDirs.push(path.join(dir) + '/*.spec.js')
      hasFile = true
    }
  })
  return specDirs.reduce((all, folderContents) => all.concat(folderContents), [])
}

4. gitlab-ci.yaml 中的改动

4.1 由js脚本来生成测试目录

其实原理非常简单,用 $(node **.js) 调用js脚本,生成一个测试目录集合给spec参数。

# gitlab-ci.yaml
test:
  stage: test
  parallel: 5
  script:
    - yarn cypress run --spec $(node scripts/cypress-parallel.js)
    - 

如果你也需要传入业务线参数,那么是这样的

# gitlab-ci.yaml
# BUSINESS_LINE 可能是 C, 可能是 B
test:
  stage: test
  parallel: 5
  script:
    - yarn cypress run --spec $(node scripts/cypress-parallel.js -b ${BUSINESS_LINE})

如果你和我一样,通过一个参数来控制测试环境,那么效果是这样的。

# gitlab-ci.yaml
#TEST_ENV 可能是 dev, 可能是 prod
test:
  stage: test
  parallel: 5
  script:
    - yarn cypress run --spec $(node scripts/cypress-parallel.js -b ${BUSINESS_LINE}) --env config=${TEST_ENV}

5. 效果如何?

5.1 耗时变小了

原来需要48分钟执行完的脚本,只需要20分钟了。

5.2 retry 成本变低了

retry 成本变低了,重跑只跑局部用例。

你可能感兴趣的:(自动化测试,Cypress,测试经验,Cypress,UI,测试,软件测试)