Jenkins教程-9-发送企业微信测试报告通知

发布于:2024-07-01 ⋅ 阅读:(20) ⋅ 点赞:(0)

上一小节我们学习了Jenkins上下游关联自动化测试任务的构建的方法,本小节我们讲解一下发送企业微信测试报告通知的方法。

1、自动化用例执行完后,使用pytest_terminal_summary钩子函数收集测试结果,存入本地status.txt文件中,供Jenkins调用

conftest.py代码如下:

#conftest.py 

def pytest_terminal_summary(terminalreporter, exitstatus, config):
    """收集测试报告summary,并存入status.txt文件中,供Jenkins调用"""
    print("pytest_terminal_summary")
    passed_num = len([i for i in terminalreporter.stats.get('passed', []) if i.when != 'teardown'])
    failed_num = len([i for i in terminalreporter.stats.get('failed', []) if i.when != 'teardown'])
    error_num = len([i for i in terminalreporter.stats.get('error', []) if i.when != 'teardown'])
    skipped_num = len([i for i in terminalreporter.stats.get('skipped', []) if i.when != 'teardown'])
    total_num = passed_num + failed_num + error_num + skipped_num
    test_result = '测试通过' if total_num == passed_num + skipped_num else '测试失败'
    duration = round((time.time() - terminalreporter._sessionstarttime), 2)

    # 定义目录路径
    directory_path = './reports/'
    # 确保文件所在的目录存在
    os.makedirs(os.path.dirname(directory_path), exist_ok=True)
    # 定义文件路径
    file_path = os.path.join(directory_path, 'status.txt')
    with open(file_path, 'w', encoding='utf-8') as f:
        f.write(f'TEST_TOTAL={total_num}\n')
        f.write(f'TEST_PASSED={passed_num}\n')
        f.write(f'TEST_FAILED={failed_num}\n')
        f.write(f'TEST_ERROR={error_num}\n')
        f.write(f'TEST_SKIPPED={skipped_num}\n')
        f.write(f'TEST_DURATION={duration}\n')
        f.write(f'TEST_RESULT={test_result}\n')

本地文件status.txt中收集的测试结果示例:

2、Jenkins中安装Environment Injector description setter 插件

Environment Injector插件用于注入环境变量

自动化测试任务配置中,添加构建步骤

填写测试结果收集文件status.txt的路径

description setter用于构建后设置任务测试结果描述

将status.txt中的的测试结果字段映射到任务描述中

执行任务构建后,任务描述中会显示构建的测试结果,如下

3、安装python-jenkins 库,读取自动化测试任务构建后的测试结果描述信息

pip install python-jenkins

代码如下

# qywechat_remind.py
import json
from datetime import datetime
import jenkins
import requests
import jmespath

host = "http://localhost:8080/"
username = 'admin'
password = 'xxxxxxxxxx'
webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=f4444444444-c1d3-47f2-be78-098f80c2d194"
env = "test"
stage = "回归测试"
job = "auto_api_test"
maintainer = "米兔1号"
server = jenkins.Jenkins(host, username=username, password=password)
last_build_number = server.get_job_info(job)['lastCompletedBuild']['number']
build_info = server.get_build_info(job, last_build_number)
console_url = build_info['url'] + "console"
report_url = build_info['url'] + 'allure'
# report_url = ip_host + report_url.split(":")[-1]
test_status = json.loads(build_info['description'])
print("构建测试结果描述信息:", test_status)

total = test_status["total"]
passed = test_status["passed"]
passed_ratio = round(passed / total, 4) * 100
failed = test_status["failed"]
failed_ratio = round((100 - passed_ratio), 2)
error = test_status["error"]
skipped = test_status["skipped"]
duration = test_status["duration"]
build_time = datetime.fromtimestamp(build_info['timestamp'] / 1000).strftime('%Y-%m-%d %H:%M:%S')
success = total == (passed + skipped) if passed != 0 else False

执行上述代码,可以看出,已经获取到jenkins任务的测试结果信息了

4、上一步获取到的测试结果信息,包装成消息体,调用企业微信机器人发送群消息接口,自动发送消息到群里

企业微信群机器人的配置和接口,请参考:群机器人配置说明 - 接口文档 - 企业微信开发者中心

企业微信发送测试结果消息的整体代码如下:

# qywechat_remind.py
import json
from datetime import datetime
import jenkins
import requests
import jmespath

host = "http://localhost:8080/"
username = 'admin'
password = 'xxxxxxxxxxxx'
webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=f333333333107-c1d3-47f2-be78-098f80c2d194"
env = "test"
stage = "回归测试"
job = "auto_api_test"
maintainer = "米兔1号"
server = jenkins.Jenkins(host, username=username, password=password)
last_build_number = server.get_job_info(job)['lastCompletedBuild']['number']
build_info = server.get_build_info(job, last_build_number)
console_url = build_info['url'] + "console"
report_url = build_info['url'] + 'allure'
# report_url = ip_host + report_url.split(":")[-1]
test_status = json.loads(build_info['description'])
total = test_status["total"]
passed = test_status["passed"]
passed_ratio = round(passed / total, 4) * 100
failed = test_status["failed"]
failed_ratio = round((100 - passed_ratio),2)
error = test_status["error"]
skipped = test_status["skipped"]
duration = test_status["duration"]
build_time = datetime.fromtimestamp(build_info['timestamp'] / 1000).strftime('%Y-%m-%d %H:%M:%S')
success = total == (passed + skipped) if passed != 0 else False

# 使用Jenkins API token 模拟登录
USERNAME = "admin"
# Jenkins API token
TOKEN = "1133333333b81ae7fd66046859f1b9833d391621a"
url_suites = f"{report_url}/data/suites.json"
# print("url_suites", url_suites)
res = requests.get(url_suites, auth=(USERNAME, TOKEN))
# print("res", res.content)
s_url = f"{report_url}/#suites/"
# print('s_url', s_url)
url_raw_list = jmespath.search(
    "children[].children[].children[].children[?status=='failed'||status=='broken'].{name:name,parentUid:parentUid,uid:uid,status:status,tags:tags}",
    res.json())
# print("url_raw_list", url_raw_list)

url_list = []
for raw in url_raw_list[0]:
    url_dict = {"name": raw["name"], "url": s_url + raw["parentUid"] + "/" + raw["uid"] + "/", "uid": raw["uid"],
                "status": raw["status"], "author": raw["tags"][0]}
    url_list.append(url_dict)
# print("url_list", url_list)

data = {
    "msgtype": "markdown",
    "markdown": {
        "content":
            f"""<font color="">钉钉oapi接口测试任务执行报告通知</font>
        >【任务名称】:<font color="comment">{job}</font>
        >【测试阶段】:<font color="comment">{stage}</font>
        >【测试结果】:<font color={"info" if success else "warning"}>{"通过~" if success else "失败!"}</font>{chr(0x1f600) if success else chr(0x1f627)}
        >【用例总数】:<font color="comment">{total}</font>
        >【通过数】:<font color="info">{passed}</font>
        >【通过率】:<font color="comment">{passed_ratio}%</font>
        >【失败数】:<font color="warning">{failed}</font>
        >【失败率】:<font color="comment">{failed_ratio}%</font>
        >【错误数】<font color="comment">{error}</font>
        >【跳过数】<font color="comment">{skipped}</font>
        >【执行人】<font color="comment">@{maintainer}</font>
        >【执行时间】:<font color="comment">{build_time}</font>
        >【执行耗时】:<font color="comment">{duration}s</font>
        >[查看测试报告]({report_url})""",
}
}
requests.post(url=webhook, json=data)
# 单个报告,详细数据
# http://localhost:8080/job/auto_api_test/76/allure/data/test-cases/9a4eba68509440c8.json

phone_mapping = {
    "zhang.san": "139xxxxxxxx",
    "li.si": "179xxxxxxxx"
}
single_url = f"{report_url}/data/test-cases/"
for case in url_list:
    url = single_url + str(case["uid"]) + ".json"
    res = requests.get(url, auth=(USERNAME, TOKEN)).json()
    case["message"] = res["statusMessage"]
author_list = list(set(jmespath.search("[*].author", url_list)))
# print("author_list",author_list)
failed_list = jmespath.search("[?status=='failed']", url_list)
broken_list = jmespath.search("[?status=='broken']", url_list)
phone_list = []
first_string = f"""<font color="">钉钉oapi接口测试任务执行错误日志通知</font>"""

failed_info = f"""
        >【失败用例】:
        """
broken_info = f""" >【错误用例】:
        """
failed_string = ""
broken_string = ""
for url_info in url_list:
    if url_info["status"] == "failed":
        failed_string += f""" ><font color="comment">{url_info["name"]}</font>
        ><font color="info">[{url_info["message"]}]({url_info["url"]})</font>
        """
    elif url_info["status"] == "broken":
        broken_string += f"""><font color="comment">{url_info["name"]}</font>
        ><font color="info">[{url_info["message"]}]({url_info["url"]})</font>
        """
if not failed_string:
    failed_string = f"""><font color="comment">无</font>"""
if not broken_string:
    broken_string = f"""><font color="comment">无</font>"""
end_string = f""" 
><font color="info">[查看测试报告]({report_url})</font>
"""
all_string = first_string + failed_info + failed_string + broken_info + broken_string + end_string
for author in author_list:
    if author in list(phone_mapping.keys()):
        phone_list.append(phone_mapping[author])
# print(phone_list)
data_mk = {
    "msgtype": "markdown",
    "markdown": {
        "content": all_string
    }
}


data_tx = {
    "msgtype": "text",
    "text": {
        "content": "请相关同事及时跟进处理!",
        "mentioned_mobile_list": phone_list
    }
}

if not success:
    # 企业微信发送错误日志
    requests.post(url=webhook, json=data_mk)
    requests.post(url=webhook, json=data_tx)

4、执行上述脚本,查看企业微信通知,如下

测试结果信息:

错误日志信息:

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走,希望可以帮助到大家!