【致敬女神】HTMLReport应用之Unittest+Python+Selenium+HTMLReport项目自动化测试实战
HTMLReport应用之Unittest+Python+Selenium+HTMLReport项目自动化测试实战
- 1 测试框架结构
- 2 技术栈
- 3 实现思路
- 3.1 使用HtmlTestRunner
- 3.2 使用HTMLReport
- 4 TestRunner参数说明
- 4.1 源码
- 4.2 参数说明
- 5 框架代码
- 5.1 common/reportOut.py
- 5.2 common/sendMain.py
- 5.3 report
- 5.3.1 xxx.html
- 5.3.2 xxx.log
- 5.3.3 xxx.xml
- 5.4 testcase
- 5.5 main.py
- 6 运行结果
『IT女神-仅以此文致敬 女性开发者』
她们在不同领域熠熠生辉,创造了无限的可能,成为了IT发展进步中不可或缺的角色。
她们在AI代码的世界里让梦想生根、开花。
不分年龄、无论背景,她们释放着热情与专业,用技术为自己代言。
致敬每一位IT女神,愿她们永远美丽、永远绽放自己独特的魅力之花。
同时,在这特殊的节日祝愿所有的女性朋友梦想成真!
注意事项:
【本文字数包含代码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, retrydef 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, retrydef 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 osdef 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_toelse:msg['To'] = ','.join(mail_to)msg['From'] = mail_frommsg['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/6ox = canvas.width / 2 + cSpace; //圆心oy = canvas.height / 2;tWidth = 60; //图例宽和高tHeight = 20;posX = cMargin;posY = cMargin; //textX = posX + tWidth + 15textY = 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_refreshself.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdnFile "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_idreturn 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 executeself.error_handler.check_response(response)File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_responseraise 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_searchself.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_idreturn 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 executeself.error_handler.check_response(response)File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_responseraise 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_clearself.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdnFile "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_idreturn 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 executeself.error_handler.check_response(response)File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_responseraise 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_refreshself.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdnFile "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_idreturn 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 executeself.error_handler.check_response(response)File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_responseraise 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_searchself.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_idreturn 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 executeself.error_handler.check_response(response)File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_responseraise 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_clearself.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdnFile "D:\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 360, in find_element_by_idreturn 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 executeself.error_handler.check_response(response)File "D:\Python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_responseraise 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 unittestclass TestCase(unittest.TestCase):@classmethoddef setUpClass(cls) -> None:cls.driver = webdriver.Chrome() # 打开Chrome浏览器cls.driver.get("http://www.baidu.com") # 输入百度网址print("============验证浏览器的基本控制==========")@classmethoddef 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*480time.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") # 输入csdntime.sleep(1)self.driver.refresh() # 刷新def test_serach_clear(self):print("4、清空输入的内容......")self.driver.find_element_by_id("kw").send_keys("csdn") # 输入csdntime.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") # 输入csdntime.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_handlesself.driver.switch_to.window(windows[-1])now_url = self.driver.current_urlm_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 osdef 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 运行结果
-
会在
report
目录下生成三个文件;
-
命令行输出:
-
测试报告:
『《假如生活欺骗了你》俄·普希金』
假如生活欺骗了你,
不要悲伤,不要心急!
忧郁的日子里须要镇静:
相信吧,快乐的日子将会来临!
心儿永远向往着未来;
现在却常是忧郁。
一切都是瞬息,一切都将会过去;
而那过去了的,就会成为亲切的怀恋。
相关文章:
【致敬女神】HTMLReport应用之Unittest+Python+Selenium+HTMLReport项目自动化测试实战
HTMLReport应用之UnittestPythonSeleniumHTMLReport项目自动化测试实战1 测试框架结构2 技术栈3 实现思路3.1 使用HtmlTestRunner3.2 使用HTMLReport4 TestRunner参数说明4.1 源码4.2 参数说明5 框架代码5.1 common/reportOut.py5.2 common/sendMain.py5.3 report5.3.1 xxx.htm…...
JAVA的16 个实用代码优化小技巧
一、类成员与方法的可见性最小化 举例:如果是一个private的方法,想删除就删除。 如果一个public的service方法,或者一个public的成员变量,删除一下,不得思考很多。 二、使用位移操作替代乘除法 计算机是使用二进制…...
并发编程的三大挑战之原子性及其解决方案
目录 一、原子性问题 1、带来原子性问题的原因 2、如何解决线程切换带来的原子问题 2.1、使用synchronized关键字来保证 2.2、使用CAS来保证原子性 2.3、使用lock锁来保证 一、原子性问题 1、带来原子性问题的原因 线程切换是带来原子的根本原因,java的并发程…...
QML动画(其他的动画)
PauseAnimation (暂停动画) 为动画提供暂停 Rectangle{id:rect1width: 100;height: 100;x:100;y:100color: "lightBlue"SequentialAnimation{running: trueColorAnimation {target: rect1;property: "color";…...
Spark 配置项
Spark 配置项硬件资源类CPU内存堆外内User Memory/Spark 可用内存Execution/Storage Memory磁盘ShuffleSpark SQLJoin 策略调整自动分区合并自动倾斜处理配置项分为 3 类: 硬件资源类 : 与 CPU、内存、磁盘有关的配置项Shuffle 类 : Shuffle 计算过程的配置项Spark SQL : Spar…...
掌握Vue3模板语法,助你轻松实现高效Web开发
Vue3作为前端开发中的一种主流框架,为我们提供了多种灵活的方式来处理模板语法。除了基础的模板语法,Vue3还提供了一些高级的语法,可以让我们更好地处理组件、响应式数据和UI逻辑等。在这篇博客中,我们将介绍Vue3中的一些高级模板…...
Jmeter+Ant+Jenkins接口自动化测试平台搭建
平台简介一个完整的接口自动化测试平台需要支持接口的自动执行,自动生成测试报告,以及持续集成。Jmeter支持接口的测试,Ant支持自动构建,而Jenkins支持持续集成,所以三者组合在一起可以构成一个功能完善的接口自动化测…...
ncnn部署(CMakelists.txt)
1. NCNN 环境安装 参考博客: 基于ncnn的yolov5模型部署 1. 1 protobuf编译 打开VS2013/VS2019的X64命令行(注意不是cmd),我这里以V32013环境进行编译 > cd <protobuf-root-dir> > mkdir build-vs2013 > cd build-vs2013 > cmake -G"NMake Makefil…...
SQL分库分表
什么是分库分表? 分库分表是两种操作,一种是分库,一种是分表。 分库分表又分为垂直拆分和水平拆分两种。 (1)分库:将原来存放在单个数据库中的数据,拆分到多个数据库中存放。 (2&…...
大数据分析案例-基于逻辑回归算法构建微博评论情感分类模型
🤵♂️ 个人主页:@艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+ 喜欢大数据分析项目的小伙伴,希望可以多多支持该系列的其他文章 大数据分析案例合集…...
0105深度优先搜索算法非递归2种实现对比-无向图-数据结构和算法(Java)
1 两种非递归实现 在前面我们解决无向图的单点通性和单点路径问题时,都用到了深度优先搜索算法。深度优先搜索算法可以用递归和非递归两种方式。这里讨论非递归实现。 无向图结构使用邻接表实现。 第一种非递归方法(推荐),代码如…...
传统手工数据采集耗时耗力?Smartbi数据填报实现数据收集分析自动化
企业在日常经营管理过程中,往往需要收集很多内外部的信息,清洗整理后再进行存储、分析、呈现、决策支持等各种作业,如何高效收集结构化数据是企业管理者经常要面对的问题。传统手工的数据采集方式不仅耗费了大量人力时间成本,还容…...
《Spring源码深度分析》第5章 Bean的加载
目录标题前言一、Bean加载入口与源码分析1、Bean加载的入口2、Bean加载源码二、FactoryBean的使用三、缓存中获取单例bean(待补充)前言 经过前面的分析,我们终于结束了对XML 配置文件的解析,接下来将会面临更大的挑战,就是对 bean 加载的探索…...
华为OD机试真题Java实现【求最大数字】真题+解题思路+代码(20222023)
求最大数字 题目 给定一个由纯数字组成以字符串表示的数值,现要求字符串中的每个数字最多只能出现2次,超过的需要进行删除;删除某个重复的数字后,其它数字相对位置保持不变。 如34533,数字3重复超过2次,需要删除其中一个3,删除第一个3后获得最大数值4533 请返回经过删…...
Java——异常机制
前言 随着对java的不断深入学习,在对语法以及编程思想有了一定的了解之后,在编程的过程中有可能会因为用户的输入不正确或者逻辑错误而出现异常或者错误,因此如何去捕捉与避免不应该出现的异常或者错误就变得十分重要。本文就介绍了java的异…...
【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(下)
系列文章目录 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(上) 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(中) 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate…...
ESP32设备驱动-土壤湿度传感器驱动
土壤湿度传感器驱动 1、土壤湿度传感器介绍 土壤湿度传感器由两个探头组成,用于测量水的体积含量。 两个探头让电流通过土壤,然后得到电阻值来测量水分值。 当有更多的水时,土壤会传导更多的电,这意味着电阻会更小。 因此,水分含量会更高。 干燥的土壤导电性差,所以当…...
公网远程连接MongoDB数据库【内网穿透】
文章目录1. 安装数据库2. 内网穿透2.1 创建隧道映射2.2 测试随机公网地址远程连接3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问MongoDB是一个基于分布式文件存储的数据库。由C语言编写。旨在为WEB应用提供…...
SQL注入——floor报错注入
目录 一,涉及到的函数 rand() floor() concat_ws() as别名,group by分组 count() 报错原理 一,涉及到的函数 rand()函数:随机返回0~1间的小数 floor()函数:小数向…...
P6入门:在EPS下创建项目(P6Professional)
引言 在 Primavera P6 中,一旦创建了企业项目结构EPS,就可以开始向该结构添加项目。项目是一组活动和数据,它们构成了创建产品或服务的计划。项目有开始日期和结束日期,可以包括活动、资源、工作分解结构、组织分解结构、日历、关…...
Linux安装及管理应用和账号和权限管理 讲解
♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放࿰…...
【JDK1.8 新特性】Stream API
1. 前言 Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API。Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力&…...
Springboot Maven打包跳过测试的五种方式总结 -Dmaven.test.skip=true
使用Maven打包的时候,可能会因为单元测试打包失败,这时候就需要跳过单元测试。也为了加快打包速度,也需要跳过单元测试。 Maven跳过单元测试五种方法。 在正式环境中运行Springboot应用,需要先打包,然后使用java -ja…...
静态链接和动态链接的区别
链接即为编译(包含预编译,编译和汇编过程)完成之后的过程,此过程又分为静态链接和动态链接两种方式。 1、静态链接 静态链接就是在生成可执行文件的时候(链接阶段),把所有需要的函数的二进制代…...
MATLAB学习笔记1
MATLAB学习笔记1 - 向量和矩阵 Matlab的数组可以是行向量,列向量,矩阵形式等 1.利用[ ]创建数组 例:包含7和9的一个数组,使用空格或,为行 x [7 9]//x是一个1*2的矩阵 y[7,9]//y是一个1*2的矩阵例:包含7和…...
Gorm -- 查询记录
文章目录查询单条记录通过结构体查询对应表指定表并将查询一条记录结果放至字典中按照主键查询查询多行记录按照主键查询使用结构体查询指定表名查询并放至字典列表中指定查询字段查询条件Where 条件(、like、in)通过结构体或字典设置查询条件或非排序Li…...
「Python 基础」错误、调试与测试
文章目录1. 错误处理2. debugassertloggingpdbIDE3. unittest编写运行setUp 与 tearDown4. doctest1. 错误处理 try:# 可能有异常的代码块r 10/int(2) except ValueError as e:# 有异常时执行,捕获指定类型及其子类型的错误print(ValueError, e) except ZeroDivis…...
17万字 JUC 看这一篇就够了(一) (精华)
JUC 今天我们来进入到 Java并发编程 JUC 框架的学习 ,内容比较多,但希望我们都能静下心来,耐心的看完这篇文章 文章目录JUC进程概述对比线程创建线程ThreadRunnableCallable线程方法APIrun startsleep yieldjoininterrupt打断线程打断 park终…...
C++右值引用/移动语义
在此之前,我们所用的引用,其实都是左值引用。 int a 10; int& ra a; 下面我们来重新认识一下引用: 而何为左值?左值引用其实是什么?请往下看~ 左值是一个表示数据的表达式(如变量名或解引用的指针)ÿ…...
小樽C++ 多章⑧ (叁) 指针与字符串、(肆) 函数与指针
目录 叁、函数与字符串 肆、函数与指针 4.1 指针作为函数参数 4.2 函数返回指针 4.3 函数指针与函数指针数组 4.4 结构体指针 小樽C 多章⑧ (壹) 指针变量https://blog.csdn.net/weixin_44775255/article/details/129031168 小樽C 多章⑧ …...
做瞹瞹嗳视频网站在线观看/网络营销招聘岗位有哪些
夜光序言: 即使身边满是凄荒、冷淡与麻木,风也会吹得柔和,心也能寻得一份温存 正文:接下来~~,实战项目:一个拥有答题页面的微信小程序 上图为实际效果图 那么如何制作出来呢~ 点击“开始测试”按钮&#x…...
邯郸建设网站/潍坊seo关键词排名
wip限制进行中的工作限制(从现在开始是WIP限制)是我在工作中遇到的最强大但违反直觉的概念之一。 当建议团队在董事会中引入WIP限制时,我听到“例如,您是说同时做更少的事情会提高您的速度吗? 你一定错了吗࿱…...
php wordpress开发教程/推广软件有哪些
let,var,const 的简单区别 let 声明的变量 有局部作用域只能声明一次 var 声明的变量没有局部作用域可以声明多次 const 声明常量声明之后不允许改变一但声明必须初始化,否则会报错...
2013电子商务网站建设/清远新闻最新
前端网站中如果存在一些让用户填写内容的表单元素的话,我们可以使用JQ中获得焦点事件和失去焦点事件,来给用户作出一些提示的内容。今天我们就说一说JQuery下获得焦点和失去焦点的事件的使用方法。jquery focus()获得焦点事件focus()方法:当通…...
网站设计步骤及关键操作怎么写/网站内部链接优化方法
最近仔细学习了一下spring技术,其中最为核心的就是IOC容器和AOP。IOC可以实现动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建、调用对象࿰…...
晋城网站建设开发/免费seo软件推荐
目录一 重用机制1 问题2 原理3 模拟重用池二 数据源同步1 问题2 解决方案2.1 并发访问&数据拷贝2.2 串行访问一 重用机制 1 问题 UITablevView是开发中最常用的实现滚动列表的方案之一, 列表的具体内容载体由UITablevViewCell, 负责一个列表可能有成千上万个cell,然而iOS…...