注意事项:
【本文字数包含代码38175字,建议慢慢看~哈哈哈】
1、以下仅为举例,具体以自身实际项目为准;
2、以下内容重点是介绍HTMLReport的应用,并不是说明如何搭建框架;
3、如果想了解框架内容,可移步博主有关测试框架的系列文章;
4、写了一个用例,用例中没有加断言,只是为了生成测试报告,可以忽略;
5、用例故意写错了3个,1个通过,是为了生成测试报告数据。
1 测试框架结构
目录/脚本 |
说明 |
common/reportOut.py |
这是是用HTMLReport 生成报告的 |
common/sendMain.py |
这个是用来发邮件,本次演示可要可不要 |
report |
是存放测试报告的,里边有3个文件,由HTMLReport 自动生成 |
testcase |
存放测试用例的 |
main.py |
框架主入口 |
2 技术栈
技术 |
版本及说明 |
Python |
V3.x(本文为3.7)===编程语言支撑 |
Selenium |
V3.141.0 ===UI元素、控件的识别、定位,以及浏览器控制等 |
HTMLReport |
生成Html测试报告 |
Unittest |
Python 自带===自动化测试框架 |
Smtplib |
Python 自带===邮件服务 |
email |
Python 自带===邮件服务 |
os |
Python 自带===系统模块 |
PyCharm |
Community 2020.2汉化版 |
操作系统 |
Windows10 旗舰版64位 |
其它 |
后续补充 |
3 实现思路
- 这里具体就是把原来生成
HtmlTestRunner
改为HTMLReport
;
3.1 使用HtmlTestRunner
# -*- coding:utf-8 -*-
# 作者:虫无涯
# 日期:2022/3/7
# 文件名称:reportOut.py
# 作用:封装测试报告功能
import time
import unittest
from common import HTMLTestRunner # 引入导入的报告模板
def report_out(test_dir, report_dir, name_project):
'''
:test_dir: 用例路径
:report_dir : 报告路径
:name_project : 项目名称=>用于报告命名及描述
:return: 无
'''
now = time.strftime("%Y_%m_%d %H_%M_%S")
discover = unittest.defaultTestLoader.discover(test_dir,pattern='test*.py') # 加载测试用例
report_name = report_dir + now + '-' + name_project+'_test_report.html' # 报告名称
with open(report_name,'wb') as f: # 运行用例生成测试报告
runner = HTMLTestRunner.HTMLTestRunner(stream=f,
title=name_project + 'WebUI Auto Testing Report',
description=(name_project + U"美多商城UI自动化功能回归测试"),
verbosity=2)
runner.run(discover)
f.close()
"""
stream:要操作的文件;
title:测试报告标题;
description:报告描述;
verbosity:报告级别。
"""
3.2 使用HTMLReport
# -*- coding:utf-8 -*-
# 作者:虫无涯
# 日期:2023/3/7
# 文件名称:reportOut.py
# 作用:封装测试报告功能
import time
import unittest
from HTMLReport import ddt, TestRunner, add_image, no_retry, retry
def report_out(test_dir, report_dir, name_project):
'''
:test_dir: 用例路径
:report_dir : 报告路径
:name_project : 项目名称=>用于报告命名及描述
:return: 无
'''
now = time.strftime("%Y_%m_%d %H_%M_%S")
discover = unittest.defaultTestLoader.discover(test_dir, pattern='test*.py') # 加载测试用例
# report_name = now + '-' + name_project + '_test_report.html' # 报告名称
test_runner = TestRunner(
report_file_name=now,
output_path=report_dir,
title=name_project,
description="关于HTMLReport的实际项目应用",
thread_count=1,
thread_start_wait=0.1,
tries=0,
delay=0,
back_off=1,
retry=True,
sequential_execution=True,
lang="cn"
)
test_runner.run(discover)
4 TestRunner参数说明
4.1 源码
class TestRunner(TemplateMixin, TestSuite):
"""测试执行器"""
def __init__(self, report_file_name: str = None, log_file_name: str = None, output_path: str = None,
title: str = None, description: str = None, tries: int = 0, delay: float = 1, back_off: float = 1,
max_delay: float = 120, retry: bool = True, thread_count: int = 1, thread_start_wait: float = 0,
sequential_execution: bool = False, lang: str = "cn", image: bool = True, failed_image: bool = False):
4.2 参数说明
参数 |
说明 |
report_file_name |
报告文件名,如果未赋值,将采用“test +时间戳” |
log_file_name |
日志文件名,如果未赋值,将采用报告文件名,如果报告文件名也没有,将采用“test +时间戳” |
output_path |
报告保存文件夹名,默认“report ” |
title |
报告标题,默认“测试报告” |
description |
报告描述,默认“无测试描述” |
tries |
重试次数 |
delay |
重试延迟间隔,单位为 秒 |
back_off |
扩展每次重试等待时间的乘数 |
max_delay |
最大重试等待时间长度,单位为 秒 |
retry |
如果为 True 表示所有用例遵循重试规则,False 只针对添加了 @retry 用例有效 |
thread_count |
并发线程数量(无序执行测试),默认数量 1 |
thread_start_wait |
各线程启动延迟,默认 0 s |
sequential_execution |
是否按照套件添加(addTests) 顺序执行, 会等待一个addTests 执行完成,再执行下一个,默认 False 。如果用例中存在 tearDownClass ,建议设置为True, 否则 tearDownClass 将会在所有用例线程执行完后才会执行。 |
lang |
("cn", "en") 支持中文与英文报告输出,默认采用中文 |
image |
默认支持添加图片,False 放弃所有图片添加 |
failed_image |
true 只有失败才添加图片,成功用例添加的图片会被删除 |
5 框架代码
5.1 common/reportOut.py
# -*- coding:utf-8 -*-
# 作者:虫无涯
# 日期:2023/3/7
# 文件名称:reportOut.py
# 作用:封装测试报告功能
import time
import unittest
from HTMLReport import ddt, TestRunner, add_image, no_retry, retry
def report_out(test_dir, report_dir, name_project):
'''
:test_dir: 用例路径
:report_dir : 报告路径
:name_project : 项目名称=>用于报告命名及描述
:return: 无
'''
now = time.strftime("%Y_%m_%d %H_%M_%S")
discover = unittest.defaultTestLoader.discover(test_dir, pattern='test*.py') # 加载测试用例
# report_name = now + '-' + name_project + '_test_report.html' # 报告名称
test_runner = TestRunner(
report_file_name=now,
output_path=report_dir,
title=name_project,
description="关于HTMLReport的实际项目应用",
thread_count=1,
thread_start_wait=0.1,
tries=0,
delay=0,
back_off=1,
retry=True,
sequential_execution=True,
lang="cn"
)
test_runner.run(discover)
5.2 common/sendMain.py
# -*- coding:utf-8 -*-
# 作者:虫无涯
# 日期:2023/3/7
# 文件名称:sendMain.py
# 作用:封装邮件服务模块
import time
import smtplib
import getpass
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import email
import os
def send_main(file_path, mail_to='xxx@126.com'):
mail_from = 'xxxx@126.com'
f = open(file_path, 'rb')
mail_body = f.read()
f.close()
# msg = email.MIMEMultipart.MIMEMultipart()
msg = MIMEMultipart()
# 构造MIMEBase对象做为文件附件内容并附加到根容器
contype = 'application/octet-stream'
maintype, subtype = contype.split('/', 1)
# 读入文件内容并格式化
data = open(file_path, 'rb')
# file_msg = email.MIMEBase.MIMEBase(maintype, subtype)
file_msg = MIMEBase(maintype, subtype)
file_msg.set_payload(data.read())
data.close()
# email.Encoders.encode_base64(file_msg)
encoders.encode_base64(file_msg)
# 设置附件头
basename = os.path.basename(file_path)
file_msg.add_header('Content-Disposition', 'attachment', filename=basename)
msg.attach(file_msg)
print(u'msg 附件添加成功')
msg1 = MIMEText(mail_body, "html", 'utf-8')
msg.attach(msg1)
if isinstance(mail_to, str):
msg['To'] = mail_to
else:
msg['To'] = ','.join(mail_to)
msg['From'] = mail_from
msg['Subject'] = u'美多商城UI自动化功能回归测试'
msg['date'] = time.strftime('%Y-%m-%d-%H_%M_%S')
print(msg['date'])
smtp = smtplib.SMTP()
smtp.connect('smtp.126.com')
smtp.login('xxx@126.com', 'xxx') # 登录账号和密码(密码为之前申请的授权码)
smtp.sendmail(mail_from, mail_to, msg.as_string())
smtp.quit()
print('email has send out !')
# if __name__=='__main__':
# sendmain('../report/2017-08-18-10_18_57_result.html')
5.3 report
5.3.1 xxx.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="cn">
<head>
<title>关于HTMLReport的实际项目应用</title>
<meta name="generator" content="HTMLReport 刘士 2.3.1"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css" media="screen">
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 14px;
}
pre {
word-wrap: break-word;
word-break: break-all;
overflow: auto;
white-space: pre-wrap
}
h1 {
font-size: 16pt;
color: gray
}
.heading {
margin-top: 0;
margin-bottom: 1ex
}
.heading .attribute {
margin-top: 1ex;
margin-bottom: 0
}
.heading .description {
margin-top: 4ex;
margin-bottom: 6ex
}
a.popup_link:hover {
color: red
}
.popup_window {
display: block;
position: relative;
left: 0;
top: 0;
padding: 10px;
background-color: #E6E6D6;
text-align: left;
font-size: 13px
}
.popup_retry_window {
padding-left: 50px;
}
#show_detail_line {
margin-top: 3ex;
margin-bottom: 1ex
}
#result_table {
width: 100%;
border-collapse: collapse;
border: 1px solid #777
}
#header_row {
color: #fff;
background-color: #777
}
#result_table td {
border: 1px solid #777;
padding: 2px;
}
#result_table td:nth-child(n+2) {
min-width: 70px;
width: 100%
}
#result_table td:nth-child(n+3) {
text-align: center;
}
#result_table td:first-of-type {
text-align: center;
min-width: 60px;
}
#total_row {
font-weight: bold
}
.passClass,
.failClass,
.errorClass,
.skipClass {
font-weight: bold
}
.passCase {
background-color: #d0e9c6
}
.failCase {
background-color: #ebcccc
}
.errorCase {
background-color: #faf2cc
}
.skipCase {
background-color: #c4e3f3
}
.hiddenRow {
display: none
}
.testcase {
margin-left: 2em
}
#popup {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
text-align: center;
display: none
}
#popup .bg {
background-color: rgba(0, 0, 0, .5);
width: 100%;
height: 100%
}
#popup img {
max-width: 100%;
max-height: 100%;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
img.pic {
cursor: pointer;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
opacity: 1;
transition: opacity 0.3s;
}
img.pic[data-src] {
opacity: 0;
}
#wrapper {
margin: 0 auto;
border-top: solid 2px #666;
}
#wrapper .lang-en {
display: none;
}
#wrapper.lang-cn p.lang-cn {
display: block;
}
#wrapper.lang-cn span.lang-cn {
display: inline;
}
#wrapper.lang-cn .lang-en {
display: none;
}
#wrapper.lang-en .lang-cn {
display: none;
}
#wrapper.lang-en p.lang-en {
display: block;
}
#wrapper.lang-en span.lang-en {
display: inline;
}
#lang ul {
float: right;
margin: 0;
padding: 2px 10px 4px 10px;
background: #666;
border-radius: 0 0 4px 4px;
list-style: none;
}
#lang li {
margin: 0;
float: left;
padding: 0 5px;
}
#lang li a {
display: block;
width: 24px;
height: 24px;
text-indent: -4em;
overflow: hidden;
background: transparent url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAHiSURBVHja1Ja/jtNAEMZ/Y2/icBdxXAMSEu/A1dBR0NJQ8CS8AQ0tb4CQgEegPgQFOh7ixJUX4vgSx96ZoUgOO3+KRDgFX7Or0Wg+f7PzeVfcnUMi4cA4OIEAARgAvY5r10AZgOGvl69Gkm4Xk9w3fJTg9f4MDz9+OA3AsSTC4OmThaQE3Bp9w+eRmy+hie2I8us3gOMABFNFkjlW5PTPIvOLAO7YVMjfC/Sd4YuK4nOGuyMiABv7v6pP7mKmACEAeK1YPuPoWU52FgkPUiaf+ngFDjCD+Q/Fproo1vrSbUPuvR4eF7kBwDRi4ynlzxkyUMrvKTZabbrPFb9Jd2qPh7BK4DGiRYFeTJmdC8nAsVKaUes72eOK6Xm2G0GaYhpXCTzPsXEBgOZN8unrktHbAddvAKrdCESwqmoItI74eILlkw0bjt4Zltdg+5hL8NhSYLGmurrCxuPN7Mv951+LAh1kLQWxBlUw68bDGtEqaStQiB0SRMWlbh1yXWPu+MIc/wzTiC0dslBQR0TArfWPwJdr21KyttLKaeJijvmaD0gTMF/z57pPt8W37E1xaylwU0iE5OhON2fgjreMVmuMXC/ntus7QYAT4BFwr+Piv4HL2xstu21Xh4jAXP77V8WfAQAixA0rudAk0AAAAABJRU5ErkJggg==") no-repeat 50% 50%;
}
#lang li a#lang-en {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAIWSURBVHja1JY/SBthGIefu1xqS6K20KFDy0kopUiHmphIByUZotRAIZOTWZzFpYtbB0uh6KJTIdQhi9pBSwmmCOpgoUSKFItTh4AU6tCr16Rn5P58XZocDrlYuAz9wfHAcbzv9/2+932/k4QQdFIyHVbHE0iAAlwFgj7HNoG6AoRzudc/A4F/28yL2l7bb269yd9QgJAsS8zMjFIufyWRuHspXqtbnsHrH8oAIQlQJyfzlaGhCNFohJ2dI1Kp/iZ3d49IJvsvvJckmJ197JlACIEsy30KgGUJBgcjFIufSacfsLnpza2tL/x4+qx15fR0Uz84hL8HjG1blEqHJJP9bGx8IpMZ8CSAMIzWq1cUhO24CSzLYWTkPisrH8lm46yuenN9fZ+br156WmRZFgQLjR3YrK2VyWSiFAp7TEw88iTAyZNca4t6e6h/P3EbzTRtxscfks9vk83G27JaPcOuVls/v6o4pltlajo9L1KpebG8vC9isbm2jMXmRDsZhiEAVWn4NTU1ysJCkenpMRYXS55cWnrPcSThUUVhzrquNEeFOjz8vOI4CrXa+aU7+d3p29YJusMYwQD3Drb7AFRd14Xf0nXdtehbfAxdkhG13/5M0HCImiTcPhC2BVIAHMefOWrbCNxYqqZpvlukaVrTIrNye4CK1JH7xpSAXuAOcN3n4KfAceNG62qch4+ygHPpv/+r+DMAXV79BpyNnBoAAAAASUVORK5CYII=");
}
.figure_ul {
text-align: center;
padding: 0;
}
.figure_li {
width: 30em;
list-style: none;
display: inline-block;
vertical-align: baseline;
}
tr {
height: 2em;
}
</style>
<script type="text/javascript">
var chartData_cn = [[1, '#1c965b', '通过'], [3, '#ff9800', '错误']];
var chartData_en = [[1, '#1c965b', 'pass'], [3, '#ff9800', 'error']];
function addClass(e, c) {
if (!isClass(e, c)) {
if (e.className) {
e.className = e.className + " " + c;
} else {
e.className = c;
}
}
}
function delClass(e, c) {
if (isClass(e, c)) {
// r = '/(?:^|\s)' + c + '(?!\S)/g';
let r = new RegExp('(?:^|\s)' + c + '(?!\S)', 'g');
e.className = e.className.replace(r, '');
}
}
function isClass(e, c) {
let r = new RegExp('(?:^|\s)' + c + '(?!\S)');
return e.className.match(r);
}
function showCase(level) {
let trs = document.getElementsByTagName("tr");
for (let i = 0; i < trs.length; i++) {
let tr = trs[i];
let id = tr.id;
if (id.substring(0, 2) === "st") {
if (level === 4 || level === 3) {
delClass(tr, 'hiddenRow');
} else {
addClass(tr, 'hiddenRow');
}
}
if (id.substring(0, 2) === "ft") {
if (level === 4 || level === 2) {
delClass(tr, 'hiddenRow');
} else {
addClass(tr, 'hiddenRow');
}
}
if (id.substring(0, 2) === "pt") {
if (level === 4 || level === 1) {
delClass(tr, 'hiddenRow');
} else {
addClass(tr, 'hiddenRow');
}
}
if (id.substring(0, 2) === "et") {
if (level === 4 || level === 5 || level === 2) {
delClass(tr, 'hiddenRow');
} else {
addClass(tr, 'hiddenRow');
}
}
if (id.substring(0, 4) === "div_") {
addClass(tr, 'hiddenRow');
}
}
}
function showClassDetail(cid, count) {
let id_list = Array(count);
let toHide = 1;
for (let i = 0; i < count; i++) {
let tid0 = "t" + cid.substring(1) + "." + (i + 1);
let tid = "f" + tid0;
let tr = document.getElementById(tid);
if (!tr) {
tid = "p" + tid0;
tr = document.getElementById(tid);
if (!tr) {
tid = "e" + tid0;
tr = document.getElementById(tid);
if (tr === null) {
tid = "s" + tid0;
tr = document.getElementById(tid);
}
}
}
id_list[i] = tid;
if (tr.className) {
toHide = 0;
}
}
for (let i = 0; i < count; i++) {
let tid = id_list[i];
if (toHide && tid.indexOf("p") !== -1) {
addClass(document.getElementById(tid), 'hiddenRow');
} else {
delClass(document.getElementById(tid), 'hiddenRow');
}
}
let trs = document.getElementsByTagName("tr");
for (let i = 0; i < trs.length; i++) {
let tr = trs[i];
let id = tr.id;
if (id.substring(0, 4) === "div_") {
addClass(tr, 'hiddenRow');
}
}
}
function showTestDetail(div_id, count, b) {
let details_div_s = document.getElementsByName(div_id);
for (let j = 0; j < details_div_s.length; j++) {
let details_div = details_div_s[j];
if (isClass(details_div, 'hiddenRow')) {
delClass(details_div, 'hiddenRow');
} else {
addClass(details_div, "hiddenRow");
}
}
for (let i = 1; i <= count; i++) {
let details_div_s = document.getElementsByName(div_id + '.' + i);
for (let j = 0; j < details_div_s.length; j++) {
let details_div = details_div_s[j];
if (details_div !== undefined) {
if (b && isClass(details_div, 'hiddenRow')) {
delClass(details_div, 'hiddenRow');
} else {
addClass(details_div, "hiddenRow");
}
}
}
}
}
function html_escape(s) {
s = s.replace(/&/g, "&");
s = s.replace(/</g, "<");
s = s.replace(/>/g, ">");
return s;
}
function goChart(dataArr) {
// 声明所需变量
var canvas, ctx;
// 图表属性
var cWidth, cHeight, cMargin, cSpace;
// 饼状图属性
var radius, ox, oy;//半径 圆心
var tWidth, tHeight;//图例宽高
var posX, posY, textX, textY;
var startAngle, endAngle;
var totleNb;
// 运动相关变量
var ctr, numctr, speed;
//鼠标移动
var mousePosition = {};
//线条和文字
var lineStartAngle, line, textPadding, textMoveDis;
// 获得canvas上下文
canvas = document.getElementById("chart");
if (canvas && canvas.getContext) {
ctx = canvas.getContext("2d");
}
initChart();
// 图表初始化
function initChart() {
// 图表信息
cMargin = 20;
cSpace = 40;
canvas.width = canvas.parentNode.getAttribute("width") * 2;
canvas.height = canvas.parentNode.getAttribute("height") * 2;
canvas.style.height = canvas.height / 2 + "px";
canvas.style.width = canvas.width / 2 + "px";
cHeight = canvas.height - cMargin * 2;
cWidth = canvas.width - cMargin * 2;
//饼状图信息
radius = cHeight * 2 / 6; //半径 高度的2/6
ox = canvas.width / 2 + cSpace; //圆心
oy = canvas.height / 2;
tWidth = 60; //图例宽和高
tHeight = 20;
posX = cMargin;
posY = cMargin; //
textX = posX + tWidth + 15
textY = posY + 18;
startAngle = endAngle = 90 * Math.PI / 180; //起始弧度 结束弧度
rotateAngle = 0; //整体旋转的弧度
//将传入的数据转化百分比
totleNb = 0;
new_data_arr = [];
for (var i = 0; i < dataArr.length; i++) {
totleNb += dataArr[i][0];
}
for (var i = 0; i < dataArr.length; i++) {
new_data_arr.push(dataArr[i][0] / totleNb);
}
totalYNomber = 10;
// 运动相关
ctr = 1;//初始步骤
numctr = 50;//步骤
speed = 1.2; //毫秒 timer速度
//指示线 和 文字
lineStartAngle = -startAngle;
line = 40; //画线的时候超出半径的一段线长
textPadding = 10; //文字与线之间的间距
textMoveDis = 200; //文字运动开始的间距
}
drawMarkers();
//绘制比例图及文字
function drawMarkers() {
ctx.textAlign = "left";
for (var i = 0; i < dataArr.length; i++) {
//绘制比例图及文字
ctx.fillStyle = dataArr[i][1];
ctx.fillRect(posX, posY + 40 * i, tWidth, tHeight);
ctx.moveTo(parseInt(posX) + 0.5, parseInt(posY + 40 * i) + 0.5);
ctx.font = 'normal 24px 微软雅黑'; //斜体 30像素 微软雅黑字体
ctx.fillStyle = dataArr[i][1]; //"#000000";
var percent = dataArr[i][2] + ":" + parseInt(100 * new_data_arr[i]) + "%";
ctx.fillText(percent, parseInt(textX) + 0.5, parseInt(textY + 40 * i) + 0.5);
}
}
//绘制动画
pieDraw();
function pieDraw(mouseMove) {
for (var n = 0; n < dataArr.length; n++) {
ctx.fillStyle = ctx.strokeStyle = dataArr[n][1];
ctx.lineWidth = 1;
var step = new_data_arr[n] * Math.PI * 2; //旋转弧度
var lineAngle = lineStartAngle + step / 2; //计算线的角度
lineStartAngle += step;//结束弧度
ctx.beginPath();
var x0 = ox + radius * Math.cos(lineAngle),//圆弧上线与圆相交点的x坐标
y0 = oy + radius * Math.sin(lineAngle),//圆弧上线与圆相交点的y坐标
x1 = ox + (radius + line) * Math.cos(lineAngle),//圆弧上线与圆相交点的x坐标
y1 = oy + (radius + line) * Math.sin(lineAngle),//圆弧上线与圆相交点的y坐标
x2 = x1,//转折点的x坐标
y2 = y1,
linePadding = ctx.measureText(dataArr[n][2]).width + 10; //获取文本长度来确定折线的长度
ctx.moveTo(parseInt(x0) + 0.5, parseInt(y0) + 0.5);
//对x1/y1进行处理,来实现折线的运动
yMove = y0 + (y1 - y0) * ctr / numctr;
ctx.lineTo(parseInt(x1) + 0.5, parseInt(yMove) + 0.5);
if (x1 <= x0) {
x2 -= line;
ctx.textAlign = "right";
ctx.lineTo(parseInt(x2 - linePadding) + 0.5, parseInt(yMove) + 0.5);
ctx.fillText(dataArr[n][2], x2 - textPadding - textMoveDis * (numctr - ctr) / numctr, y2 - textPadding);
} else {
x2 += line;
ctx.textAlign = "left";
ctx.lineTo(parseInt(x2 + linePadding) + 0.5, parseInt(yMove) + 0.5);
ctx.fillText(dataArr[n][2], x2 + textPadding + textMoveDis * (numctr - ctr) / numctr, y2 - textPadding);
}
ctx.stroke();
}
//设置旋转
ctx.save();
ctx.translate(ox, oy);
ctx.rotate((Math.PI * 2 / numctr) * ctr / 2);
//绘制一个圆圈
ctx.strokeStyle = "rgba(0,0,0," + 0.5 * ctr / numctr + ")"
ctx.beginPath();
ctx.arc(0, 0, (radius + 20) * ctr / numctr, 0, Math.PI * 2, false);
ctx.stroke();
for (var j = 0; j < dataArr.length; j++) {
//绘制饼图
endAngle = endAngle + new_data_arr[j] * ctr / numctr * Math.PI * 2; //结束弧度
ctx.beginPath();
ctx.moveTo(0, 0); //移动到到圆心
ctx.arc(0, 0, radius * ctr / numctr, startAngle, endAngle, false); //绘制圆弧
ctx.fillStyle = dataArr[j][1];
if (mouseMove && ctx.isPointInPath(mousePosition.x * 2, mousePosition.y * 2)) {
ctx.globalAlpha = 0.8;
}
ctx.closePath();
ctx.fill();
ctx.globalAlpha = 1;
startAngle = endAngle; //设置起始弧度
if (j == dataArr.length - 1) {
startAngle = endAngle = 90 * Math.PI / 180; //起始弧度 结束弧度
}
}
ctx.restore();
if (ctr < numctr) {
ctr++;
setTimeout(function () {
//ctx.clearRect(-canvas.width,-canvas.width,canvas.width*2, canvas.height*2);
ctx.clearRect(-canvas.width, -canvas.height, canvas.width * 2, canvas.height * 2);
drawMarkers();
pieDraw();
}, speed *= 1.085);
}
}
//监听鼠标移动
var mouseTimer = null;
canvas.addEventListener("mousemove", function (e) {
e = e || window.event;
if (e.offsetX || e.offsetX == 0) {
mousePosition.x = e.offsetX;
mousePosition.y = e.offsetY;
} else if (e.layerX || e.layerX == 0) {
mousePosition.x = e.layerX;
mousePosition.y = e.layerY;
}
clearTimeout(mouseTimer);
mouseTimer = setTimeout(function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawMarkers();
pieDraw(true);
}, 10);
});
}
function load() {
let el_wrapper = document.getElementById('wrapper');
document.getElementById('lang-cn').onclick = function () {
el_wrapper.className = 'lang-cn';
goChart(chartData_cn);
};
document.getElementById('lang-en').onclick = function () {
el_wrapper.className = 'lang-en';
goChart(chartData_en);
};
let nav_lang = (location.hash || '').replace(/#/, '');
if (nav_lang === 'cn' || nav_lang === 'en') el_wrapper.className = 'lang-' + nav_lang;
let images = document.getElementsByClassName("pic");
let lens = images.length;
let popup = document.getElementById("popup");
function showBig(src, title, alt) {
document.getElementById("popup-img").setAttribute("src", src)
document.getElementById("popup-img").setAttribute("title", title)
document.getElementById("popup-img").setAttribute("alt", alt)
popup.style.display = "block";
popup.style.zIndex = "999999";
}
function show(event) {
event = event || window.event;
let target = document.elementFromPoint(event.clientX, event.clientY);
showBig(target.src, target.title, target.alt);
}
for (let i = 0; i < lens; i++) images[i].onclick = show;
popup.onclick = function () {
document.getElementById("popup-img").removeAttribute("src")
document.getElementById("popup-img").removeAttribute("title")
document.getElementById("popup-img").removeAttribute("alt")
popup.style.display = "none";
popup.style.zIndex = "-1";
};
[].forEach.call(document.querySelectorAll('img.pic[data-src]'), function (img) {
img.setAttribute('src', img.getAttribute('data-src'));
img.onload = function () {
img.removeAttribute('data-src');
};
});
draw()
}
function draw() {
goChart(chartData_cn);
}</script>
</head>
<body onload="load()">
<div id="wrapper" class="lang-cn">
<div id="lang">
<ul>
<li>
<a href="#cn" id="lang-cn" title="简体中文">cn</a>
</li>
<li>
<a href="#en" id="lang-en" title="English">en</a>
</li>
</ul>
</div>
<div class='heading'>
<h1>关于HTMLReport的实际项目应用</h1>
<table>
<tr><td style="width: 100%; vertical-align: top;">
<p class='attribute'>
<strong>
<span class="lang-cn">启动时间:</span>
<span class="lang-en">Start Time:</span>
</strong> 2023-03-07 17:15:55
</p>
<p class='attribute'>
<strong>
<span class="lang-cn">结束时间:</span>
<span class="lang-en">End Time:</span>
</strong> 2023-03-07 17:16:09
</p>
<p class='attribute'>
<strong>
<span class="lang-cn">运行时长:</span>
<span class="lang-en">Duration:</span>
</strong> 0:00:13.857089
</p>
<p class='attribute'>
<strong>
<span class="lang-cn">结果:</span>
<span class="lang-en">Status:</span>
</strong>
<span class="lang-cn">合计:</span>
<span class="lang-en">Total:</span>4
<span class="lang-cn">通过:</span>
<span class="lang-en">Passed:</span>1
<span class="lang-cn">失败:</span>
<span class="lang-en">Failed:</span>0
<span class="lang-cn">错误:</span>
<span class="lang-en">Error:</span>3
<span class="lang-cn">跳过:</span>
<span class="lang-en">Skipped:</span>0
</p>
<p class='description'>关于HTMLReport的实际项目应用</p>
</td>
<td>
<div height="400" width="600">
<canvas id="chart" style="border: 1px solid #A4E2F9;"> 你的浏览器不支持HTML5 canvas </canvas>
</div>
</td>
</tr>
</table>
</div> <a href='2023_03_07 17_15_55.log'>
<span class="lang-cn">下载日志文件</span>
<span class="lang-en">Download log file</span>
</a>
<p id='show_detail_line'>筛选
<a href='javascript:showCase(0)'>
<span class="lang-cn">摘要</span>
<span class="lang-en">Summary</span>
</a>
<a href='javascript:showCase(1)'>
<span class="lang-cn">通过</span>
<span class="lang-en">Pass</span>
</a>
<a href='javascript:showCase(2)'>
<span class="lang-cn">失败</span>
<span class="lang-en">FAIL</span>
</a>
<a href='javascript:showCase(5)'>
<span class="lang-cn">异常</span>
<span class="lang-en">Error</span>
</a>
<a href='javascript:showCase(3)'>
<span class="lang-cn">跳过</span>
<span class="lang-en">Skip</span>
</a>
<a href='javascript:showCase(4)'>
<span class="lang-cn">全部</span>
<span class="lang-en">All</span>
</a>
</p>
<table id='result_table'>
<tr id='header_row'>
<th>
<span class="lang-cn">序号</span>
<span class="lang-en">NO</span>
</th>
<th>
<span class="lang-cn">测试组/测试用例</span>
<span class="lang-en">Test Group/Test case</span>
</th>
<th>
<span class="lang-cn">计数</span>
<span class="lang-en">Count</span>
</th>
<th>
<span class="lang-cn">通过</span>
<span class="lang-en">Passed</span>
</th>
<th>
<span class="lang-cn">失败</span>
<span class="lang-en">Failed</span>
</th>
<th>
<span class="lang-cn">错误</span>
<span class="lang-en">Erroneous</span>
</th>
<th>
<span class="lang-cn">跳过</span>
<span class="lang-en">Skipped</span>
</th>
<th>
<span class="lang-cn">统计</span>
<span class="lang-en">Statistics</span>
</th>
<th>
<span class="lang-cn">重试</span>
<span class="lang-en">Tries</span>
</th>
<th>
<span class="lang-cn">查看</span>
<span class="lang-en">View</span>
</th>
</tr>
<tr class='errorClass'>
<td>c1</td>
<td>test_baidu.TestCase</td>
<td>4</td>
<td class="passCase">1</td>
<td class="failCase">0</td>
<td class="errorCase">3</td>
<td class="skipCase">0</td>
<td style="text-align:right;">25.00%</td>
<td>0</td>
<td>
<a href="javascript:showClassDetail('c1',4)">
<span class="lang-cn">细节</span>
<span class="lang-en">Detail</span>
</a>
</td>
</tr>
<tr id='et1.1'>
<td>et1.1</td>
<td class='errorCase' colspan='7'>
<div class='testcase'>test_back_refresh</div>
</td>
<td class='errorCase'>
<div class='testcase' style="margin-left: auto;">0</div>
</td>
<td class='errorCase' align='center'>
<a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_et1.1.1',1, false)">
<span class="lang-cn">错误</span>
<span class="lang-en">error</span>
</a>
</td>
</tr>
<tr id='div_S_et1.1.1' name='div_et1.1.1' class="hiddenRow">
<td colspan='10'>
<div class="popup_window">
<div style='text-align: right; color:red;cursor:pointer'
onclick="document.getElementById('div_S_et1.1.1').className = 'hiddenRow'">
<a onfocus='this.blur();'>[x]</a>
</div>
<pre>et1.1.1:
2023-03-07 17:15:58,071 23748 INFO result.py(70) - 测试延迟启动:0.1s
2023-03-07 17:15:58,183 23748 INFO result.py(73) - 开始测试: test_back_refresh (test_baidu.TestCase)
2023-03-07 17:15:58,329 23748 ERROR result.py(191) - 测试产生错误: test_back_refresh (test_baidu.TestCase)
Traceback (most recent call last):
File "F:\Automated-UITest-demo-update - htmlreport\testcase\test_baidu.py", line 43, in test_back_refresh
self.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdn
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
'value': value})['value']
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="kw"]"}
(Session info: chrome=110.0.5481.178)
2023-03-07 17:15:58,330 23748 INFO result.py(96) - 测试结束: test_back_refresh (test_baidu.TestCase)
2023-03-07 17:15:58,330 23748 INFO result.py(97) - 耗时: 0.14696788787841797
</pre>
<div><ul class='figure_ul'></ul></div>
</div>
</td>
</tr><tr id='et1.2'>
<td>et1.2</td>
<td class='errorCase' colspan='7'>
<div class='testcase'>test_search</div>
</td>
<td class='errorCase'>
<div class='testcase' style="margin-left: auto;">0</div>
</td>
<td class='errorCase' align='center'>
<a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_et1.2.1',1, false)">
<span class="lang-cn">错误</span>
<span class="lang-en">error</span>
</a>
</td>
</tr>
<tr id='div_S_et1.2.1' name='div_et1.2.1' class="hiddenRow">
<td colspan='10'>
<div class="popup_window">
<div style='text-align: right; color:red;cursor:pointer'
onclick="document.getElementById('div_S_et1.2.1').className = 'hiddenRow'">
<a onfocus='this.blur();'>[x]</a>
</div>
<pre>et1.2.1:
2023-03-07 17:15:58,330 23748 INFO result.py(70) - 测试延迟启动:0.1s
2023-03-07 17:15:58,434 23748 INFO result.py(73) - 开始测试: test_search (test_baidu.TestCase)
2023-03-07 17:16:00,445 23748 ERROR result.py(191) - 测试产生错误: test_search (test_baidu.TestCase)
Traceback (most recent call last):
File "F:\Automated-UITest-demo-update - htmlreport\testcase\test_baidu.py", line 26, in test_search
self.driver.find_element_by_id("kw").send_keys("helloworld") # 输入“helloworld”
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
'value': value})['value']
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="kw"]"}
(Session info: chrome=110.0.5481.178)
2023-03-07 17:16:00,445 23748 INFO result.py(96) - 测试结束: test_search (test_baidu.TestCase)
2023-03-07 17:16:00,445 23748 INFO result.py(97) - 耗时: 2.0103440284729004
</pre>
<div><ul class='figure_ul'></ul></div>
</div>
</td>
</tr><tr id='et1.3'>
<td>et1.3</td>
<td class='errorCase' colspan='7'>
<div class='testcase'>test_serach_clear</div>
</td>
<td class='errorCase'>
<div class='testcase' style="margin-left: auto;">0</div>
</td>
<td class='errorCase' align='center'>
<a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_et1.3.1',1, false)">
<span class="lang-cn">错误</span>
<span class="lang-en">error</span>
</a>
</td>
</tr>
<tr id='div_S_et1.3.1' name='div_et1.3.1' class="hiddenRow">
<td colspan='10'>
<div class="popup_window">
<div style='text-align: right; color:red;cursor:pointer'
onclick="document.getElementById('div_S_et1.3.1').className = 'hiddenRow'">
<a onfocus='this.blur();'>[x]</a>
</div>
<pre>et1.3.1:
2023-03-07 17:16:00,445 23748 INFO result.py(70) - 测试延迟启动:0.1s
2023-03-07 17:16:00,561 23748 INFO result.py(73) - 开始测试: test_serach_clear (test_baidu.TestCase)
2023-03-07 17:16:00,566 23748 ERROR result.py(191) - 测试产生错误: test_serach_clear (test_baidu.TestCase)
Traceback (most recent call last):
File "F:\Automated-UITest-demo-update - htmlreport\testcase\test_baidu.py", line 49, in test_serach_clear
self.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdn
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
'value': value})['value']
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="kw"]"}
(Session info: chrome=110.0.5481.178)
2023-03-07 17:16:00,567 23748 INFO result.py(96) - 测试结束: test_serach_clear (test_baidu.TestCase)
2023-03-07 17:16:00,567 23748 INFO result.py(97) - 耗时: 0.0060002803802490234
</pre>
<div><ul class='figure_ul'></ul></div>
</div>
</td>
</tr><tr id='pt1.4'>
<td>pt1.4</td>
<td class='passCase' colspan='7'>
<div class='testcase'>test_windows_size</div>
</td>
<td class='passCase'>
<div class='testcase' style="margin-left: auto;">0</div>
</td>
<td class='passCase' align='center'>
<a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_pt1.4.1',1, false)">
<span class="lang-cn">通过</span>
<span class="lang-en">pass</span>
</a>
</td>
</tr>
<tr id='div_S_pt1.4.1' name='div_pt1.4.1' class="hiddenRow">
<td colspan='10'>
<div class="popup_window">
<div style='text-align: right; color:red;cursor:pointer'
onclick="document.getElementById('div_S_pt1.4.1').className = 'hiddenRow'">
<a onfocus='this.blur();'>[x]</a>
</div>
<pre>pt1.4.1:
2023-03-07 17:16:00,567 23748 INFO result.py(70) - 测试延迟启动:0.1s
2023-03-07 17:16:00,670 23748 INFO result.py(73) - 开始测试: test_windows_size (test_baidu.TestCase)
2023-03-07 17:16:05,441 23748 INFO result.py(172) - 测试执行通过: test_windows_size (test_baidu.TestCase)
2023-03-07 17:16:05,442 23748 INFO result.py(96) - 测试结束: test_windows_size (test_baidu.TestCase)
2023-03-07 17:16:05,442 23748 INFO result.py(97) - 耗时: 4.770826101303101
</pre>
<div><ul class='figure_ul'></ul></div>
</div>
</td>
</tr>
<tr id='total_row'>
<td> </td>
<td>
<span class="lang-cn">合计</span>
<span class="lang-en">Total</span>
</td>
<td>4</td>
<td class="passCase">1</td>
<td class="failCase">0</td>
<td class="errorCase">3</td>
<td class="skipCase">0</td>
<td style="text-align:right;">25.00%</td>
<td>0</td>
<td> </td>
</tr>
</table>
<div id='ending'> </div>
<div id="popup">
<div class="bg">
<img id="popup-img"/>
</div>
</div>
</div>
</body>
</html>
5.3.2 xxx.log
2023-03-07 17:15:55,952 25872 INFO test_runner.py(162) - 预计并发线程数:1
2023-03-07 17:15:58,071 23748 INFO result.py(70) - 测试延迟启动:0.1s
2023-03-07 17:15:58,183 23748 INFO result.py(73) - 开始测试: test_back_refresh (test_baidu.TestCase)
2023-03-07 17:15:58,329 23748 ERROR result.py(191) - 测试产生错误: test_back_refresh (test_baidu.TestCase)
Traceback (most recent call last):
File "F:\Automated-UITest-demo-update - htmlreport\testcase\test_baidu.py", line 43, in test_back_refresh
self.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdn
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
'value': value})['value']
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="kw"]"}
(Session info: chrome=110.0.5481.178)
2023-03-07 17:15:58,330 23748 INFO result.py(96) - 测试结束: test_back_refresh (test_baidu.TestCase)
2023-03-07 17:15:58,330 23748 INFO result.py(97) - 耗时: 0.14696788787841797
2023-03-07 17:15:58,330 23748 INFO result.py(70) - 测试延迟启动:0.1s
2023-03-07 17:15:58,434 23748 INFO result.py(73) - 开始测试: test_search (test_baidu.TestCase)
2023-03-07 17:16:00,445 23748 ERROR result.py(191) - 测试产生错误: test_search (test_baidu.TestCase)
Traceback (most recent call last):
File "F:\Automated-UITest-demo-update - htmlreport\testcase\test_baidu.py", line 26, in test_search
self.driver.find_element_by_id("kw").send_keys("helloworld") # 输入“helloworld”
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
'value': value})['value']
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="kw"]"}
(Session info: chrome=110.0.5481.178)
2023-03-07 17:16:00,445 23748 INFO result.py(96) - 测试结束: test_search (test_baidu.TestCase)
2023-03-07 17:16:00,445 23748 INFO result.py(97) - 耗时: 2.0103440284729004
2023-03-07 17:16:00,445 23748 INFO result.py(70) - 测试延迟启动:0.1s
2023-03-07 17:16:00,561 23748 INFO result.py(73) - 开始测试: test_serach_clear (test_baidu.TestCase)
2023-03-07 17:16:00,566 23748 ERROR result.py(191) - 测试产生错误: test_serach_clear (test_baidu.TestCase)
Traceback (most recent call last):
File "F:\Automated-UITest-demo-update - htmlreport\testcase\test_baidu.py", line 49, in test_serach_clear
self.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdn
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
'value': value})['value']
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="kw"]"}
(Session info: chrome=110.0.5481.178)
2023-03-07 17:16:00,567 23748 INFO result.py(96) - 测试结束: test_serach_clear (test_baidu.TestCase)
2023-03-07 17:16:00,567 23748 INFO result.py(97) - 耗时: 0.0060002803802490234
2023-03-07 17:16:00,567 23748 INFO result.py(70) - 测试延迟启动:0.1s
2023-03-07 17:16:00,670 23748 INFO result.py(73) - 开始测试: test_windows_size (test_baidu.TestCase)
2023-03-07 17:16:05,441 23748 INFO result.py(172) - 测试执行通过: test_windows_size (test_baidu.TestCase)
2023-03-07 17:16:05,442 23748 INFO result.py(96) - 测试结束: test_windows_size (test_baidu.TestCase)
2023-03-07 17:16:05,442 23748 INFO result.py(97) - 耗时: 4.770826101303101
2023-03-07 17:16:09,611 25872 INFO test_runner.py(199) -
Pass test_windows_size (test_baidu.TestCase)
2023-03-07 17:16:09,612 25872 ERROR test_runner.py(201) -
Error test_back_refresh (test_baidu.TestCase)
Error test_search (test_baidu.TestCase)
Error test_serach_clear (test_baidu.TestCase)
2023-03-07 17:16:09,614 25872 INFO test_runner.py(219) -
测试结束!
运行时间: 0:00:13.857089
共计执行用例数量:4
执行成功用例数量:1
执行失败用例数量:0
跳过执行用例数量:0
产生异常用例数量:3
5.3.3 xxx.xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="关于HTMLReport的实际项目应用" errors="3" failures="0" tests="4" skipped="0" time="13.857089" >
<testsuite name="test_baidu.TestCase" id="0" errors="3" skipped="0" tests="4" failures="0" time="6.934138298034668">
<testcase name="test_back_refresh" classname="test_baidu.TestCase.test_back_refresh" time="0.14696788787841797">
<error/>
</testcase>
<testcase name="test_search" classname="test_baidu.TestCase.test_search" time="2.0103440284729004">
<error/>
</testcase>
<testcase name="test_serach_clear" classname="test_baidu.TestCase.test_serach_clear" time="0.0060002803802490234">
<error/>
</testcase>
<testcase name="test_windows_size" classname="test_baidu.TestCase.test_windows_size" time="4.770826101303101">
</testcase>
</testsuite>
</testsuites>
5.4 testcase
- 注意:这个用例只是说明测试报告的生成,没有对用例严格按照标准写,比如断言等
# -*- coding:utf-8 -*-
# 作者:虫无涯
# 日期:2023/3/7
# 文件名称:test_baidu.py
# Function:打开百度网主页,在搜索栏输入“helloworld”
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import unittest
class TestCase(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.driver = webdriver.Chrome() # 打开Chrome浏览器
cls.driver.get("http://www.baidu.com") # 输入百度网址
print("============验证浏览器的基本控制==========")
@classmethod
def tearDownClass(cls) -> None:
cls.driver.quit() # 关闭浏览器
def test_search(self):
print("1、搜索helloworld.并回车......")
time.sleep(2)
self.driver.find_element_by_id("kw").send_keys("helloworld") # 输入“helloworld”
time.sleep(2)
self.driver.find_element_by_id("kw").send_keys(Keys.ENTER) # 回车进行搜索
time.sleep(2)
self.driver.maximize_window() # 最大化当前窗口
def test_windows_size(self):
print("2、浏览器窗口大小缩小为640*480......")
time.sleep(2)
self.driver.set_window_size(640, 480) # 控制浏览器显示尺寸为640*480
time.sleep(0.5)
self.driver.maximize_window() # 最大化当前窗口
time.sleep(2)
def test_back_refresh(self):
print("3、先进行浏览器后退,再次输入csdn进行搜索")
self.driver.back()
self.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdn
time.sleep(1)
self.driver.refresh() # 刷新
def test_serach_clear(self):
print("4、清空输入的内容......")
self.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdn
time.sleep(2)
self.driver.find_element_by_id("kw").clear()
time.sleep(0.5)
def csdn(self):
print("5、进入csdn官网")
self.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdn
time.sleep(2)
self.driver.find_element_by_id("kw").send_keys(Keys.ENTER) # 回车进行搜索
time.sleep(2)
self.driver.find_element_by_xpath("//*[@id='1']/h3/a[1]").click()
time.sleep(2)
windows = self.driver.window_handles
self.driver.switch_to.window(windows[-1])
now_url = self.driver.current_url
m_get_url = "https://www.csdn.net/"
if now_url == m_get_url:
print("经过判断,已经进入csdn官网!!")
else:
print("未进入到csdn官网,请检查代码!")
if __name__ == "__main__":
unittest.main()
5.5 main.py
# -*- coding:utf-8 -*-
# 作者:虫无涯
# 日期:2023/3/7
# 文件名称:main.py
# 作用:框架的主入口函数
import time
from common.reportOut import report_out
from common.sendMain import send_main
import os
def acquire_report_address(reports_address):
#这里方法略获取最新的测试报告,作为邮件的附件
def run_case():
print("======开始执行!!!======")
curpath = os.path.dirname(os.path.realpath(__file__))
report_dir = os.path.join(curpath, "report/") # 测试报告存放目录
test_dir = os.path.join(curpath, "testcase/") # 测试用例读取目录
name_project = "关于HTMLReport的实际项目应用"
report_out(test_dir, report_dir, name_project)
time.sleep(5)
# 这里方法略,调用邮件方法即可
print("======执行结束!!!======")
if __name__ == '__main__':
run_case()
6 运行结果