目錄
前言? ? ? ??
一、項(xiàng)目框架
1.項(xiàng)目迭代
2.項(xiàng)目時(shí)序圖
3.項(xiàng)目測(cè)試執(zhí)行
二、項(xiàng)目具體實(shí)現(xiàn)
1.創(chuàng)建流水線(xiàn)
2.拉取代碼
3.執(zhí)行測(cè)試代碼
4.生成測(cè)試報(bào)告
5.報(bào)告內(nèi)容解讀
6.數(shù)據(jù)統(tǒng)計(jì)
7.郵件通知
8.企業(yè)微信通知
三、項(xiàng)目遇到的問(wèn)題
1.go test -args?
2.go test生成html格式的報(bào)告
3.數(shù)據(jù)統(tǒng)計(jì)問(wèn)題
4.相對(duì)路徑問(wèn)題
5.錯(cuò)誤排查問(wèn)題
前言? ? ? ??
? ? ? ?目前我們的項(xiàng)目體系流程不夠完善,我們針對(duì)這一現(xiàn)象引入了“測(cè)試驅(qū)動(dòng)開(kāi)發(fā)”觀念,在開(kāi)發(fā)測(cè)試部署階段可以節(jié)省一部分工作量,對(duì)于比較復(fù)雜的場(chǎng)景,也可以編寫(xiě)一些測(cè)試工具。我們都知道如果僅靠傳統(tǒng)的手工測(cè)試(偏功能)會(huì)存在很多的漏洞,為了提高迭代效率,引入自動(dòng)化測(cè)試、CI/CD,在項(xiàng)目測(cè)試階段、預(yù)上線(xiàn)、上線(xiàn)等各個(gè)階段都能快速通過(guò)上述手段發(fā)現(xiàn)問(wèn)題,保障產(chǎn)品質(zhì)量。
? ? ?
一、項(xiàng)目框架
????????在日常測(cè)試過(guò)程中,需要驗(yàn)證測(cè)試環(huán)境&線(xiàn)上環(huán)境API接口,為了更方便,研究了通過(guò)Jenkins構(gòu)建自動(dòng)化項(xiàng)目并生成HTML報(bào)告。接下來(lái)會(huì)詳細(xì)介紹項(xiàng)目構(gòu)建步驟和遇到的問(wèn)題。
1.項(xiàng)目迭代
2.項(xiàng)目時(shí)序圖
3.項(xiàng)目測(cè)試執(zhí)行
二、項(xiàng)目具體實(shí)現(xiàn)
1.創(chuàng)建流水線(xiàn)
(1)新建任務(wù)
(2)選擇流水線(xiàn)或者復(fù)制現(xiàn)有流水線(xiàn)任務(wù)
(3)配置流水線(xiàn)
(4)pipeline腳本的基本框架
#!groovy
pipeline {
????agent any
????environment {
????????GO_BINARY = "go"
????????TEST_REPORT_PATH = "test-report.xml"
????}
????stages {
????????stage('checkout') {
????????????steps {
????????????????sh"""
????????????????????echo "steps one"
????????????????"""
????????????}
????????}
????????stage('unit-test') {
????????????steps {
????????????????echo "step two"
????????????}
????????}
????????stage('api-test') {
????????????steps {
????????????????sh """
???????????????????ehco "step three"
???????????????????"""
????????????}
????????}
????}
????post {
????????always {
????????????echo "clean over..."
????????????echo "send email"
????????}
????????success {
????????????echo 'Build && Test Succeeded.'
????????}
????????failure {
????????????echo 'Build && Test Failured.'
????????}
????}
}
對(duì)應(yīng)在jenkins上的階段視圖:
2.拉取代碼
repoURL = "git拉取代碼地址"
rootPath = "/var/jenkins_work/workspace/pid-openapi-test-report"
repoPath = "${rootPath}/$BUILD_ID"
...
stages {
????stage('checkout') {
????????steps {
????????????sh"""
????????????????export PATH="${arcPath}:${goRoot}:${kubectlRoot}:${makeRoot}:$PATH"
????????????????git clone --depth 1 ${repoURL} ${repoPath}
????????????"""
????????}
????}
????...
}
3.執(zhí)行測(cè)試代碼
利用go test命令執(zhí)行代碼。執(zhí)行g(shù)o test會(huì)進(jìn)行全代碼編譯的,會(huì)拉取所有的依賴(lài),所以需要提前配置go環(huán)境變量。
go test運(yùn)行指定模塊、指定優(yōu)先級(jí)的測(cè)試用例,eg:
go test -v ./test/storage/... '-run=^Test+/TestP0' -json
./test/storage/?storage在openapi-go項(xiàng)目中的代碼目錄
'-run=^Test+/TestP0'?^Test指定Test打頭的suite,/TestP0指定該suite下的用例。這樣可以將模塊storage、用例名稱(chēng)TestP0參數(shù)化為MODULE_NAME、PRIORITY,并在jenkins上的參數(shù)化構(gòu)建中進(jìn)行賦值。
配置完成后go test可以寫(xiě)成這樣了:
go test -v ./test/$MODULE_NAME/... ??-run="^Test"+"/Test"+$PRIORITY
4.生成測(cè)試報(bào)告
安裝go-test-report
go get github.com/vakenbolt/go-test-report/
執(zhí)行生成html格式測(cè)試報(bào)告的命令,會(huì)在當(dāng)前目錄生成一個(gè)test_report.html
go test -v ./test/$MODULE_NAME/... ??-run="^Test"+"/Test"+$PRIORITY ??-json | go-test-report
jenkins發(fā)布報(bào)告的pipeline script:
stage('Report') { ??????????
????????steps {
????????????echo "report"
????????????publishHTML (target: [
????????????allowMissing: false,
????????????alwaysLinkToLastBuild: false,
????????????keepAll: true,
????????????reportDir: '$BUILD_ID/test-output',
????????????reportFiles: 'test_report.html',
????????????reportName: "HTML Report"
????????])
????????}
????}
然后就可以在jenkins查看該報(bào)告了
5.報(bào)告內(nèi)容解讀
失敗的用例是紅色,通過(guò)的用例是綠色。失敗日志需要關(guān)注assert部分的日志,包括報(bào)錯(cuò)行數(shù)、期望值與實(shí)際值的比較結(jié)果。
6.數(shù)據(jù)統(tǒng)計(jì)
在測(cè)試代碼執(zhí)行結(jié)果及報(bào)告都有了之后就可以統(tǒng)計(jì)自已需要的數(shù)據(jù),然后放在郵件內(nèi)容里進(jìn)行發(fā)送。
先分析下html源文件的內(nèi)容,找到自已想要的數(shù)據(jù)。
groovy自帶解析html格式的庫(kù),但是不太好用。這里采用awk解析數(shù)據(jù)。
注:substr(s,p,n) 返回字符串s從p開(kāi)始長(zhǎng)度為n的部分
def genReportBody() {
// 生成測(cè)試報(bào)告內(nèi)容
def testReport = readFile("$BUILD_ID/test-output/test_report.html")
// 獲取執(zhí)行時(shí)間
sh(script: 'pwd')
def duration = sh(script: 'grep "Duration:" '+"$BUILD_ID/test-output/test_report.html"+' | awk \'{print substr($6,9,length($6)-17)}\'', returnStdout: true).trim()
echo duration
def runtime = duration.split("\\.")[0].trim()
echo runtime
// 獲取總數(shù)量
def total = sh(script: 'grep "Total:" '+"$BUILD_ID/test-output/test_report.html"+' | awk \'{print substr($5,9,length($5)-26)}\'', returnStdout: true).trim()
// 獲取通過(guò)率
def passedCount = sh(script: 'grep "Passed:" '+"$BUILD_ID/test-output/test_report.html"+' | awk \'{print substr($5,9,length($5)-17)}\'', returnStdout: true).trim()
def skippedCount = sh(script: 'grep "Skipped:" '+"$BUILD_ID/test-output/test_report.html"+' | awk \'{print substr($5,9,length($5)-17)}\'', returnStdout: true).trim()
def failedCount = sh(script: 'grep "Failed:" '+"$BUILD_ID/test-output/test_report.html"+' | awk \'{print substr($5,9,length($5)-17)}\'', returnStdout: true).trim()
def passedRate = String.format("%.2f", passedCount.toInteger()/(total.toInteger()-skippedCount.toInteger()) * 100)
7.郵件通知
組裝郵件中的內(nèi)容
// 生成測(cè)試報(bào)告
def reportContent = """
<h2>OpenAPI Test Report (${MODULE_NAME})</h2>
<p>Environment: ${ENV}</p>
<p>Test Time: ${runtime}s</p>
<h3>Test Cases:</h3>
<ul>
<a href="https://jenkins地址/view/pid/job/${JOB_NAME}/$BUILD_ID/HTML_20Report/" target="_blank">https://jenkins地址/view/pid/job/${JOB_NAME}/$BUILD_ID/HTML_20Report/</a>
</ul>
<p>Pass Rate: ${passedRate}% </p>
<p>Test Range: ${PRIORITY}</p>
<h3>Failures: ${failedCount}</h3>
"""
發(fā)送郵件,在發(fā)送郵件前將無(wú)用的測(cè)試數(shù)據(jù)清除
post {
????????always {
????????????sh """
????????????????mv ${repoPath}/test-output ~/temp
????????????????rm -rf ${repoPath}/*
????????????????mv ~/temp/test-output ${repoPath}/
????????????"""
????????????echo "clean over..."
????????????emailext body: ?genReportBody(),
????????????????????subject: 'Test Report',
????????????????????// to: 'env.RECIPIENTS',
????????????????????to: '${RECIPIENT_LIST}',
????????????????????mimeType: 'text/html'
????????????// from: '郵件發(fā)送地址'
????????}
????????success {
????????????echo 'Build && Test Succeeded.'
????????}
????????failure {
????????????echo 'Build && Test Failured.'
????????}
}
8.企業(yè)微信通知
三、項(xiàng)目遇到的問(wèn)題
1.go test -args?
利用該命令自定義參數(shù)時(shí)發(fā)現(xiàn)-args后面所有東西都當(dāng)成agrs的值,且阻斷后面所有指令的執(zhí)行。后來(lái)在stackoverflow看見(jiàn)一個(gè)人發(fā)了同樣的問(wèn)題,我想到去看下官方說(shuō)明
In addition to the build flags, the flags handled by 'go test' itself are:
-args
????Pass the remainder of the command line (everything after -args)
????to the test binary, uninterpreted and unchanged.
????Because this flag consumes the remainder of the command line,
????the package list (if present) must appear before this flag.
上面的everything after -args和執(zhí)行實(shí)際效果是一樣。這樣通過(guò)命令行方式來(lái)切換環(huán)境的做法是行不通,于是采用多個(gè)配置文件的方式,全部存放在jenkins機(jī)器的~/conf目錄。
切換方式
if [ $ENV = "test" ]
then
????echo 'cp test .env'
????cp /home/jenkins/conf/.env ${repoPath}/test
????cp /home/jenkins/conf/.env.storage ${repoPath}/test/storage/v1/.env
elif [ $ENV = "dev" ]
then
????#statements
????echo 'cp dev .env'
????cp /home/jenkins/conf/.env.dev ${repoPath}/test/.env
????cp /home/jenkins/conf/.env.storage.dev ${repoPath}/test/storage/v1/.env
????
elif [ $ENV = "prod" ]
then
????echo 'cp prod .env'
????cp /home/jenkins/conf/.env.prod ${repoPath}/test/.env
????cp /home/jenkins/conf/.env.storage.prod ${repoPath}/test/storage/v1/.env
fi
2.go test生成html格式的報(bào)告
最開(kāi)始也是打算接入allure報(bào)告,但是發(fā)現(xiàn)go test并不支持,所以采用了go-test-report。發(fā)布的第一版的go?test report時(shí)并不是長(zhǎng)這樣的
而是像下面這樣不帶css樣式的
解決方法:在jenkins-->系統(tǒng)管理-->腳本命令行,輸入以下命令
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")
3.數(shù)據(jù)統(tǒng)計(jì)問(wèn)題
網(wǎng)上有很多groovy統(tǒng)計(jì)xml格式的文件,沒(méi)找到能很好解析html格式的工具,想到awk這個(gè)工具。
def passedCount = sh(script: 'grep "Passed:" '+"$BUILD_ID/test-output/test_report.html"+' | awk \'{print substr($5,9,length($5)-17)}\'', returnStdout: true).trim()
4.相對(duì)路徑問(wèn)題
我們用IDE編寫(xiě)用例時(shí)直接就可以執(zhí)行了,這種情況下go會(huì)把該用例所在的目錄當(dāng)成pwd目錄;而流水線(xiàn)中g(shù)o?test是在項(xiàng)目根目錄下執(zhí)行的,這時(shí)go是把項(xiàng)目根目錄當(dāng)成pwd目錄的。這樣用例中使相對(duì)路徑eg:.env、../.env等都會(huì)執(zhí)行失敗。
解決方法:利用runtime獲取當(dāng)前執(zhí)行路徑,然后代碼中生成項(xiàng)目根目錄,以該路徑為基點(diǎn)再去拼接文件的路徑,盡量不要使相對(duì)路徑。
5.錯(cuò)誤排查問(wèn)題
后面發(fā)現(xiàn)現(xiàn)有的腳本case編寫(xiě)如果有一個(gè)報(bào)錯(cuò),全部都是紅色,找到報(bào)錯(cuò)點(diǎn)不是很方便,修改腳本case為:
func (s *JobBatchGetSuite) TestP0_Normal() {
s.Run("TestSuccessJobBatchGet", func() {
s.TestSuccessJobBatchGet()
})
}
func (s *JobBatchGetSuite) TestP1_Normal() {
s.Run("TestJobBatchGetJobIdsTooMuch", func() {
s.TestJobBatchGetJobIdsTooMuch()
})
}
在jenkins上執(zhí)行后,報(bào)告展示更為直觀。
今天的分享就到此結(jié)束嘍~文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-801025.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-801025.html
到了這里,關(guān)于測(cè)試驅(qū)動(dòng)開(kāi)發(fā):基于Jenkins+GoTest+HTML的持續(xù)化集成的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!