7 月 15 日,MeterSphere 一站式开源持续测试平台发布 v1.20.10 LTS 版本。
本文将分享如何通过 GitLab CI/CD 集成 MeterSphere 一站式开源持续测试平台,助力企业的 DevOps 落地。
一、DevOps 与 QA 的关系
在落地并实践 DevOps(开发运营一体化)的过程中,深入人们脑海中的是 “Dev+Ops” 的组成与融合,它形象地揭示了敏捷化软件工程致力于打破部门墙的努力,并从软件全生命周期的视角来管理并优化端到端的交付流程。DevOps 发端于敏捷运动,也是敏捷软件研发的进一步延伸,它是一种实践,也是一种文化。维基百科曾经将 DevOps 诠释为软件研发、质量保障和技术运营三者的结合。
个人认为,这在一定程度上强调了 QA(即 Quality Assurance,质量保障)在 DevOps 体系中不可或缺的地位与存在。在 DevOps 发展的初期,人们曾经疑惑测试在未来软件研发中的地位,导致很多测试人员甚至产生了职业危机感。
但是伴随着 DevOps 实践的不断深入,QA 非但没有消失,反而越来越被重视。测试被分散并融入到了研发与交付过程的各个不同阶段,对测试人员的技能及其对专业技能的掌握有了更高的要求,也要求其更多地从质量保障的角度参与软件交付的过程。
诚然,不同的人对于 DevOps 也许有着不同的理解和定义,但是一些基本的共识被证明可以助力 DevOps 的持续价值交付。例如:
■ 质量内建:团队所有成员对质量负责,而不仅仅是测试人员对质量负责。质量保障活动贯穿于软件研发的各个阶段,并通过流程与工具形成自我管理的组织;
■ 自动化:更多地采用自动化和自动化测试,它是 DevOps 持续交付能运转的基础与驱动,努力朝着测试金字塔的模型迈进;
■ 持续反馈:在每一个阶段、每一个代码分支上都有测试活动的介入,依托于自动化测试,尽早测试、频繁测试、按需测试,将问题尽可能地消灭在萌芽之中。
二、GitLab 及其 CI/CD
GitLab 是主流的研发管理和 DevOps 平台之一,内置了 Git 代码管理、持续集成、发布包管理、Issue 问题跟踪、研发过程跟踪等从设计到投产的 DevOps 全流程。
GitLab CI/CD 是 Gitlab 内置的免费 CI/CD 引擎。作为持续集成的工具载体,它通过 Git 仓库根目录下的.gitlab-ci.yml 进行 Pipeline 编排,并通过 GitLab Runner 执行脚本。GitLab CI/CD 这种跟代码仓库紧密绑定、开发友好的编排和使用方式,决定了其在 DevOps 自动化流水线中,更适合使用 Shell 脚本来实现包括测试在内的自动化任务。
三、MeterSphere 一站式开源持续测试平台
MeterSphere 作为一款一站式的开源持续测试平台,遵循 GPL v3 开源许可协议,涵盖测试跟踪、接口测试、UI 测试和性能测试等功能,全面兼容 JMeter、Selenium 等主流开源标准,帮助企业用户在持续开发、持续集成和持续部署的基础上,构建全生命周期的持续测试平台,应对 DevOps 企业环境落地的挑战。
四、GitLab CI/CD 为什么要集成 MeterSphere?
■ DevOps 的天然要求
在 DevOps 时代,开发人员在 “右移”,运维人员在 “左移”,而测试人员既 “左移” 又 “右移”。测试是融入在 DevOps 交付全过程中的,在代码的开发分支、集成分支、构建分支、发布分支,甚至分支的合并与制品包的部署时,都需要测试介入,尽管这中间涉及的可能是不同类型的测试。
图片来源:Dan Ashby
对于上述这些发布前的测试,尤其是开发阶段的测试,基于 API 接口进行自动化测试实现功能验证,是较为经济高效的方式,也是现在软件从业者们普遍采用的方式。这种自动化测试不是为了发现更多的 Bug,而是为了以高效的方式验证功能的正确性。
■ 工具使然
GitLab 是强大且优秀的 DevOps 平台,拥有广泛的使用群体。如前所述,其涵盖的功能涉及研发、安全合规、监控、分析、反馈等多方面。但是 GitLab 本身并不包含自动化测试的功能,也没有集成特定的自动化工具。而 MeterSphere 开源持续测试平台本身拥有良好的开源生态、活跃的社区用户、简单易用的产品特性和完善的 REST API 接口。
同时,得益于 gitlab-ci 的灵活性,使得 GitLab CI/CD 与 MeterSphere 形成很好的优势互补。在 MeterSphere 中创建并维护自动化测试用例,GitLab CI/CD 通过 API 调用远程触发自动化测试用例。开发人员在检入代码时,可以随时触发开发分支的流水线,执行构建、部署、测试等一系列检查验证,保障代码质量。
五、集成案例展示
本例子主要演示 GitLab CI/CD 通过 gitlab-ci 调用 MeterSphere 中已经维护好的自动化测试计划并返回报告 URL,自动化测试计划关联了 2 个自动化场景用例。被测系统是额外搭建的另外一套独立的 MeterSphere 环境,MeterSphere eats its own dog food : - )
MeterSphere 开源持续测试平台最近上线了 MeterSphere 专业测试云(www.metersphere.com),本示例采用专业测试云作为自动化测试的用例管理与执行环境。
准备一台配置 4C8G 以上的 CentOS 7 x64 Linux 虚拟机,磁盘容量可以配置 100GB 左右,最好能访问互联网。如果不能访问互联网,也可以通过 MeterSphere 开源社区获取离线安装包。
具体安装过程比较简单,参考 MeterSphere 官方文档(
https://metersphere.io/docs/quick_start/quick_start/),一键部署即可。
访问 MeterSphere 专业测试云主页(www.metersphere.com)进行注册。
注册完成后就进入租户管理页面,点击右侧绿色的 “进入工作台” 按钮,进入测试的工作页面(这点不好找,首次使用很容易迷路 )。
进入 MeterSphere 专业测试云工作台后,依次创建项目、接口定义、单接口用例和场景用例。
① 导入接口定义
② 创建项目环境
在环境中设置 accessKey、secretKey 等通用环境变量;
设置全局前置脚本,如被测系统鉴权相关的 Signature 生产方法;
③ 创建场景 1
通过接口/project/listAll 获取项目列表;
④ 创建场景 2
循环创建用户并验证,再通过循环清理数据,将所创建的用户删除并验证;
创建测试计划 Sprint-1,并关联所创建的场景 1 和场景 2;
① 注册 GitLab 账号
在极狐https://jihulab.com创建项目,并检入代码;
② 提交脚本至 Git 仓库
将脚本 triggerTestPlan.sh 检入到 git 仓库;
脚本用法:triggerTestPlan.sh $accessKey $secretKey $projectName $envName $testPlanName $host
其中:
■ accessKey 与 secretKey 在登录 MeterSphere 后,事先生成;
■ projectName 为自动化测试用例、测试计划所在的 MeterSphere 项目名称;
■ envName 为测试计划所执行的运行环境,在 MeterSphere 项目设置中事先配置好;
■ testPlanName 为将要执行的 MeterSphere 测试计划名称,它创建在 “测试跟踪” 模块下;
■ Host 为 MeterSphere 服务器域名或 IP 地址,如” cloud.metersphere.com“(不带 “http://” 或 “https://” 前缀 )。
以下为 triggerTestPlan.sh 脚本:
!/bin/bash
accessKey=${1}
secretKey=${2}
projectName=${3}
envName=${4}
testPlanName=${5}
HOST=${6}
projectId="projectId"
envId="environmentId"
testPlanId="testPlanId"
userId="userId"
reportURL="reportURL"
testReportId="retrieveReportId"
keySpec=$(echo -n "${secretKey}" | od -A n -t x1 | tr -d ' ')
iv=$(echo -n "${accessKey}" | od -A n -t x1 | tr -d ' ')
currentTimeMillis=$(date +%s000)
seed=${accessKey}\|$currentTimeMillis
signature=$(printf %s "${seed}" | openssl enc -e -aes-128-cbc -base64 -K ${keySpec} -iv ${iv})
# get Project ID through project name
getProjectId()
{
RESULT=$(curl -k -s -H "accesskey: ${accessKey}" -H "signature: ${signature}" -H "Content-Type: application/json" https://${HOST}/project/listAll)
projectId=$(printf '%s\n' "${RESULT}" | jq '.data[] | select(.name == "'"${projectName}"'")' |jq .id)
}
getEnvId()
{
proj_id=`echo $1|awk -F "\"" '{print $2}'`
RESULT=$(curl -k -s -H "accesskey: ${accessKey}" -H "signature: ${signature}" -H "Content-Type: application/json" https://${HOST}/api/environment/list/${proj_id})
envId=$(printf '%s\n' "${RESULT}" | jq '.data[] | select(.name == "'"${envName}"'")' |jq .id)
}
# get Test Plan ID through plan name
getTestPlanId()
{
proj_id=$1
plan_name=$2
BODY='{"projectId": '$proj_id'}'
RESULT=$(curl -k -s -X POST -H "accesskey: ${accessKey}" -H "signature: ${signature}" -H "Content-Type: application/json" https://${HOST}/test/plan/list/1/100 -d "${BODY}")
testPlanId=$(printf '%s\n' "${RESULT}" | jq '.data.listObject[] | select(.name == "'"${plan_name}"'")' |jq .id)
}
# get current user ID
getUserId()
{
RESULT=$(curl -k -s -H "accesskey: ${accessKey}" -H "signature: ${signature}" -H "Content-Type: application/json" https://${HOST}/currentUser)
userId=$(printf '%s\n' "${RESULT}" | jq '.data.id')
}
#Execute the Test Plan which associated the api test scenarios
runTestPlan()
{
proj_id=$1
plan_id=$2
user_id=$3
env_id=$4
BODY='{"mode": "serial", "testPlanId": '${plan_id}',"envMap":{'${proj_id}':'${env_id}'}, "tirggerMode": "API","userId": '${user_id}' }'
#In addtion to the above JSON,the request body could be composed of more parameters
RESULT=$(curl -k -s -X POST -H "accessKey: ${accessKey}" -H "signature: ${signature}" -H "Content-Type: application/json" https://${HOST}/test/plan/run -d "${BODY}")
testReportId=$(echo $RESULT | jq -r '.data')
}
getReportSharedId()
{
report_id=$1
BODY='{"customData":"'${report_id}'","shareType":"PLAN_DB_REPORT","lang":null}'
RESULT=$(curl -k -s -X POST -H "accessKey: ${accessKey}" -H "signature: ${signature}" -H 'Content-Type: application/json' https://${HOST}/share/info/generateShareInfoWithExpired -d "${BODY}")
reportSharedId=$(echo $RESULT | jq -r '.data.shareUrl')
}
getProjectId
#echo "PROJECT_ID: ${projectId}"
getEnvId $projectId
#echo "Env_ID: ${envId}"
getTestPlanId $projectId ${testPlanName}
#echo "TestPlanId: ${testPlanId}"
getUserId
runTestPlan $projectId $testPlanId $userId $envId
getReportSharedId $testReportId
REPORTURL="https://${HOST}/sharePlanReport${reportSharedId}"
echo "Please visit URL: ${REPORTURL} for test report"
③ 配置流水线
GitLab 中配置 CI/CD 流水线,通过脚本 triggerTestPlan.sh 触发 MeterSphere 自动化测试计划;
image: alpine:latest
stages:
- build
- deploy
- api test
build-job:
stage: build
script:
- echo "Thid is a build job"
deploy-job:
stage: deploy
script:
- echo "Thid is a deploy job"
test-job: # This job calls MeterSphere API to run API test.
stage: api test
before_script:
- sh env_prepare.sh #必要的测试环境准备
script:
- sh triggerTestPlan.sh $accessKey $secretKey $projectName $envName $testPlanName $host
④ 配置变量
CI/CD 脚本中的变量,可以事先设置相应的变量值,将执行相关的值参数化,实现脚本的重用;
⑤ 执行流水线
在执行流水线过程中,可以打印执行过程的日志,并在执行结束后,将 MeterSphere 的测试报告 URL 返回给 GitLab,开发或测试人员可以在 GitLab 界面直接打开测试报告;
通过点击执行结果中的测试报告 URL,可以跳转至 MeterSphere 报告页面。
六、总结与展望
作为在研发测试领域被大家认可并采纳的优秀工具平台,GitLab 和 MeterSphere 都采用了开源的模式,通过社区与一线使用者保持密切的互动。
GitLab CI/CD 与 MeterSphere 的集成为 DevOps 的落地和使用提供了新的选择。在未来,我们希望将这种集成进一步地固化成 GitLab CI/CD 的模版,以开箱即得的方式助力企业的 DevOps 落地。