持续交付之.Net项目单测自动化框架落地(入门篇)
【摘要】 自动化测试框架和平台形形色色,只有最合适项目团队的才是最好的,本文带着大家快速搭建一个属于自己.Net项目的轻型单测自动化框架。
前言
自动化测试框架和平台形形色色,只有最合适项目团队的才是最好的,本文带着大家快速搭建一个属于自己.Net项目的轻型单测自动化框架。
落地方案
技术架构
主要特点
- 使用 MSTest 作为项目运行框架,方便执行测试用例,生成测试结果
- 使用开源工具作为报告驱动,二次美化功能,界面更美观,内容清晰,实现在线 HtmlReport
- 实现测试历史结果趋势分析
- 实现钉钉自动化通知及跳转功能
- 实现覆盖度结果上传 SonarQube
- 使用 Jenkins 作为自助式测试,一站式测试平台,方便自动编译,自动运行测试脚本,发送测试报告,通知等
技术选型
- 单测框架:MSTest
- 单测报告框架:Trxer
- 覆盖度扫描工具:Opencover
- 覆盖度报告框架:ReportGenerator
- 覆盖度报告服务:Tomcat
- 自动通知:钉钉webhook & python
- Jenkins 插件:
- Git plugin:拉取代码
- Version Number Plugin:生成部分版本号
- window 批处理:执行bat脚本
- SonarScanner for MSBuild:静态代码扫描
- MSBuild Plugin:代码编译
- MSTest plugin:执行测试
- HTML Publisher plugin:单测在线 HtmlReport
- Groovy Plugin:设置 HtmlReport 插件 css 生效
相关工具链接:
- trxer:https://github.com/NivNavick/trxer
- opencover:https://github.com/OpenCover/opencover
- ReportGenerator:https://github.com/danielpalme/ReportGenerator
核心步骤
1)设置上传覆盖度结果上传到 SonarQube :
/d:propertyKey="TestResults\TestResults.trx"
/d:sonar.cs.opencover.reportsPaths="TestResults\CodeCoverageResults.xml"
参考下图:
2)执行 MSBuild 编译,这里参考自己的项目设置:
3)执行单测及覆盖度扫描脚本如下:
::删除原文件
rmdir /s/q TestResults
mkdir TestResults
::执行单元测试及覆盖度扫描
"C:\opencover.4.7.922\opencover.console.exe" -target:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\MSTest.exe" -targetargs:/testcontainer:"D:\Jenkins-workspace\Jenkins\workspace\bin\unitTest\UnitTestServer.dll" -filter:+[*]* -register:user -mergebyhash -output:TestResults\CodeCoverageResults.xml
::修改文件名
cd TestResults
ren *.trx TestResults.trx
::生成单元测试报告
"D:\trxer\TrxerConsole\bin\Debug\TrxerConsole.exe" TestResults.trx
::生成单元测试覆盖度报告
"C:\ReportGenerator_4.1.4\net47\ReportGenerator.exe" -reports:"CodeCoverageResults.xml" -targetdir:"Coverage_%BUILD_NUMBER%"
::拷贝到服务器
xcopy Coverage_%BUILD_NUMBER% \\xxx.xxx.xxx.xxx\webapps\v3c\coverage\%JOB_NAME%\Coverage_%BUILD_NUMBER% /I/F/E/Y
参考下图:
注意:
- Tomcat 服务的主机需要开启共享文件(window)
配置 Groovy script,让 HtmlReport 插件 css 能用,同时不用担心 Jenkins 重启:
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")
参考下图:
5)构建后操作,发布单测 HtmlReport:
注意:
- HTML directory to archive:报告路径
- Index page[s] :报告索引名称
- Keep past HTML reports:保留报告
设置统计分析测试结果 :
7)post build task 执行钉钉通知:
Python脚本:
# coding=utf-8
'''
@author: zuozewei
@file: notification.py
@time: 2019/4/25 18:00
@description:dingTalk通知类
'''
import os, jenkins, configparser, requests, json, time
from dingtalkchatbot.chatbot import DingtalkChatbot
from jsonpath import jsonpath
# 获取 Jenkins 变量
JOB_NAME = str(os.getenv("JOB_NAME"))
BUILD_URL = str(os.getenv("BUILD_URL")) + "console"
BUILD_VERSION = str(os.getenv("BUILD_VERSION"))
JENKINS_HOME = os.getenv("JENKINS_HOME")
BUILD_NUMBER = str(os.getenv("BUILD_NUMBER"))
WORKSPACE = os.getenv("WORKSPACE")
versionPath = JENKINS_HOME + "\workspace\Version.ini"
config = configparser.ConfigParser()
config.read(versionPath)
xxx_Major = config.get("xxx", "xxx_Major")
xxx_Minor = config.get("xxx", "xxx_Minor")
xxx_Build = config.get("xxx", "xxx_Build")
xxx_Revision = config.get("xxx", "xxx_Revision")
VERSION = xxx_Major + "." + xxx_Minor + "." + xxx_Build + "." + xxx_Revision
reportUrl = 'http://xxx.xxx.xxx.xxx:8080/view/xxx/job/' + JOB_NAME + '/' + BUILD_NUMBER + '/HTML_20Report/'
# 连接jenkins
server = jenkins.Jenkins(url="http://xxx.xxx.xxx.xxx:8080", username='xxx', password="xxx")
testresult = ''
packagePath = WORKSPACE + "\\package.ini"
overageReportUrl = 'http://xxx.xxx.xxx.xxx/xxx/coverage/' + JOB_NAME + '/Coverage_' + BUILD_NUMBER
def unitTestNotification():
title = 'xxx单测通知'
last_build_number = server.get_job_info(JOB_NAME)['lastCompletedBuild']['number']
build_info = server.get_build_info(JOB_NAME, last_build_number)
# dict字典转json数据
build_info_json = json.dumps(build_info)
# 把json字符串转json对象
build_info_jsonobj = json.loads(build_info_json)
failCount = jsonpath(build_info_jsonobj, '$.actions..failCount')
skipCount = jsonpath(build_info_jsonobj, '$.actions..skipCount')
totalCount = jsonpath(build_info_jsonobj, '$.actions..totalCount')
successCount = totalCount[0] - skipCount[0] - failCount[0]
successRate = round((successCount / totalCount[0]) * 100, 1)
# 判断测试结果
if successRate == 100:
testresult = 'SUCCESS'
else:
testresult = 'FAILURE'
testFail = '#### ' + JOB_NAME + ' - UnitTest # ' + BUILD_NUMBER + ' \n' + \
'##### <font color=#FF0000 size=6 face="黑体">测试结果: ' + testresult + '</font> \n' + \
'##### **版本类型**: ' + '开发版' + '\n' + \
'##### **当前版本**: ' + VERSION + '\n' + \
'##### **用例数**: ' + str(totalCount[0]) + '个 \n' + \
'##### **通过率**: ' + str(successRate) + '% \n' + \
'##### **成功**: ' + str(successCount) + '个 \n' + \
'##### **失败**: ' + str(failCount[0]) + '个 \n' + \
'##### **忽略**: ' + str(skipCount[0]) + '个 \n' + \
'##### **测试报告**: [查看详情](' + reportUrl + ') \n' + \
'##### **覆盖率报告**: [查看详情](' + overageReportUrl + ') \n' + \
'##### **关注人**: @18610902487 \n' + \
'> ###### xxx技术团队 \n '
testSuccess = '#### ' + JOB_NAME + ' - UnitTest # ' + BUILD_NUMBER + ' \n' + \
'##### **测试结果**: ' + testresult + '\n' + \
'##### **版本类型**: ' + '开发版' + '\n' + \
'##### **当前版本**: ' + VERSION + '\n' + \
'##### **用例数**: ' + str(totalCount[0]) + '个 \n' + \
'##### **通过率**: ' + str(successRate) + '% \n' + \
'##### **成功**: ' + str(successCount) + '个 \n' + \
'##### **失败**: ' + str(failCount[0]) + '个 \n' + \
'##### **忽略**: ' + str(skipCount[0]) + '个 \n' + \
'##### **测试报告**: [查看详情](' + reportUrl + ') \n' + \
'##### **覆盖率报告**: [查看详情](' + overageReportUrl + ') \n' + \
'> ###### xxx技术团队 \n '
if testresult == 'SUCCESS':
dingText = testSuccess
else:
dingText = testFail
sendding(title, dingText)
def sendding(title, content):
at_mobiles = ['186xxxx2487']
Dingtalk_access_token_v3c = 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxx'
# 初始化机器人小丁
xiaoding1 = DingtalkChatbot(Dingtalk_access_token_v3c)
# Markdown消息@指定用户
xiaoding1.send_markdown(title=title, text=content, at_mobiles=at_mobiles)
if __name__ == "__main__":
unitTestNotification()
功能展示
单元测试
测试结果趋势:
在线 HtmlReport:
覆盖度分析
访问 Tomcat 报告 web 服务:
钉钉通知
遇到的坑
单元测试中依赖的数据文件或者dll等非引用关系的资源导致测试失败(找不到依赖),开发case的时候需要加标识 DeploymentItem:
小结
本文带着大家结合 Jenkins 快速入门搭建一款属于自己Net项目单测自动化框架,希望你能有启发。
本文资源:
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)