GitLab CI 並行執行 Cypress 測試指令碼
技術標籤:自動化測試Cypress測試經驗CypressUI 測試軟體測試
文章目錄
隨著用例越來越多,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"
配置後,效果如圖
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 成本變低了,重跑只跑區域性用例。