uiautotest_pytest_demo/conftest.py

235 lines
9.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
# @Version: Python 3.9
# @Time : 2023/2/2 16:05
# @Author : chenyinhua
# @File : conftest.py
# @Software: PyCharm
# @Desc: 这是文件的描述信息
from config.global_vars import GLOBAL_VARS
from loguru import logger
import pytest
from config.settings import test, live, RunDriver, REPORT_TITLE, PROJECT_NAME, TESTER, DEPARTMENT
from py._xmlgen import html # 安装pytest-html版本最好是2.1.1
from time import strftime
from selenium import webdriver
from selenium.webdriver.chrome.options import Options as CH_Options
from selenium.webdriver.firefox.options import Options as FF_Options
from datetime import datetime
import os
from config.project_path import IMG_DIR
# ------------------------------------- START: 配置运行环境 ---------------------------------------#
def pytest_addoption(parser):
"""
pytest_addoption 可以让用户注册一个自定义的命令行参数,方便用户将数据传递给 pytest
这个 Hook 方法一般和 内置 fixture pytestconfig 配合使用pytest_addoption 注册命令行参数pytestconfig 通过配置对象读取参数的值;
:param parser:
:return:
"""
parser.addoption(
# action="store" 默认,只存储参数的值,可以存储任何类型的值,此时 default 也可以是任何类型的值,而且命令行参数多次使用也只能生效一个,最后一个值覆盖之前的值;
# action="append"将参数值存储为一个列表用append模式将可以在pytest命令行方式执行测试用例的同时多次向程序内部传递自定义参数对应的参数值
"--env", action="store",
default="test",
choices=["test", "live"], # choices 只允许输入的值的范围
type=str,
help="将命令行参数--env添加到pytest配置对象中通过--env设置当前运行的环境host"
)
@pytest.fixture(scope="session", autouse=True)
def get_config(request):
"""
从配置对象中读取自定义参数的值
"""
# 根据指定的环境,获取指定环境的域名以及用例数据文件类型
env = request.config.getoption("--env")
if env.lower() == "live":
config_data = live
else:
config_data = test
for item in config_data:
for k, v in item.items():
GLOBAL_VARS[k] = v
logger.info(f"当前环境变量为:{GLOBAL_VARS}")
# ------------------------------------- END: 配置运行环境 ---------------------------------------#
# ------------------------------------- START: 启动浏览器驱动 ---------------------------------------#
@pytest.fixture(scope="session", autouse=True)
def init_driver():
"""
定义浏览器驱动
:return:
"""
try:
driver_type = RunDriver.driver_type
driver_path = RunDriver.driver_path
logger.debug(f"运行的浏览器:{driver_type}, 驱动执行路径:{driver_path}")
if driver_type.lower() == "chrome":
# 本地chrome浏览器
# driver = webdriver.Chrome() # 不指定浏览器驱动路径的写法
driver = webdriver.Chrome(executable_path=driver_path)
driver.maximize_window()
driver.implicitly_wait(10)
driver.maximize_window()
driver.delete_all_cookies() # 清除浏览器所有缓存
elif driver_type.lower() == "firefox":
# 本地firefox浏览器
# driver = webdriver.Firefox() # 不指定浏览器驱动路径的写法
driver = webdriver.Firefox(executable_path=driver_path)
driver.maximize_window()
driver.implicitly_wait(10)
driver.maximize_window()
driver.delete_all_cookies() # 清除浏览器所有缓存
elif driver_type.lower() == "chrome-headless":
# chrome headless模式
# 参数说明参考地址https://github.com/GoogleChrome/chrome-launcher/blob/master/docs/chrome-flags-for-tools.md#--enable-automation
chrome_option = CH_Options()
chrome_option.add_argument("--headless")
chrome_option.add_argument("--no-sandbox") # 注意linux运行必须要有这个
chrome_option.add_argument("--window-size=1920x1080")
# driver = webdriver.Chrome(options=chrome_option) # 不指定浏览器驱动路径的写法
driver = webdriver.Chrome(executable_path=driver_path, options=chrome_option)
driver.implicitly_wait(10)
driver.delete_all_cookies() # 清除浏览器所有缓存
elif driver_type.lower() == "firefox-headless":
# firefox headless模式
firefox_options = webdriver.FirefoxOptions()
firefox_options.add_argument("--headless")
firefox_options.add_argument("--disable-gpu")
# driver = webdriver.Firefox(options=firefox_options) # 不指定浏览器驱动路径的写法
driver = webdriver.Firefox(options=firefox_options, executable_path=driver_path)
driver.implicitly_wait(10)
driver.delete_all_cookies() # 清除浏览器所有缓存
else:
logger.error("driver驱动类型定义错误")
raise NameError("driver驱动类型定义错误")
except Exception as e:
logger.error(f"初始化dirver的异常请检查以下几点1. driver_path的路径是否配置正确 2. driver版本是否与浏览器兼容{e}")
raise NameError(f"driver异常请检查以下几点1. driver_path的路径是否配置正确 2. driver版本是否与浏览器兼容 {e}")
GLOBAL_VARS["driver"] = driver
yield driver
# 关闭浏览器
driver.quit()
# ------------------------------------- END: 启动浏览器驱动 ---------------------------------------#
# ------------------------------------- START: 报告处理 ---------------------------------------#
def pytest_html_report_title(report):
"""
修改报告标题
"""
report.title = REPORT_TITLE
def pytest_configure(config):
"""
# 在测试运行前修改Environment部分信息配置测试报告环境信息
"""
# 给环境表 添加项目名称及开始时间
config._metadata["项目名称"] = PROJECT_NAME
config._metadata['开始时间'] = strftime('%Y-%m-%d %H:%M:%S')
# 给环境表 移除packages 及plugins
config._metadata.pop("Packages")
config._metadata.pop("Plugins")
@pytest.hookimpl(tryfirst=True)
def pytest_sessionfinish(session, exitstatus):
"""
在测试运行后修改Environment部分信息
"""
# 给环境表 添加 项目环境
session.config._metadata['项目环境'] = GLOBAL_VARS.get("host", "")
def pytest_html_results_summary(prefix, summary, postfix):
"""
修改Summary部分的信息
"""
prefix.extend([html.p(TESTER)])
prefix.extend([html.p(DEPARTMENT)])
def pytest_html_results_table_header(cells):
"""
修改结果表的表头
"""
# 往表格中增加一列"用例描述",并且给"用例描述"增加排序
cells.insert(2, html.th('用例描述', class_="sortable", col="name"))
# 往表格中增加一列"执行时间",并且给"执行时间"增加排序
cells.insert(3, html.th('执行时间', class_="sortable time", col="time"))
# 移除表格最后一列
cells.pop()
def pytest_html_results_table_row(report, cells):
"""
修改结果表的表头后给对应的行增加值
"""
# 往列"用例描述"插入每行的值
cells.insert(2, html.td(report.description))
# 往列"执行时间"插入每行的值
cells.insert(3, html.td(strftime("%Y-%m-%d %H:%M:%S"), class_="col-time"))
# 移除表格最后一列
cells.pop()
def pytest_html_results_table_html(report, data):
"""如果测试通过,则显示这条用例通过啦!"""
if report.passed:
del data[:]
data.append(html.div("这条用例通过啦!", class_="empty log"))
@pytest.mark.hookwrapper
def pytest_runtest_makereport(item, call):
"""
1. 测试方法的文档注释作为结果表的Description的值
2. 测试用例失败进行截图操作,并将截图追加到测试报告中
"""
pytest_html = item.config.pluginmanager.getplugin("html")
outcome = yield
# 获取调用结果的测试报告返回一个report对象
# report对象的属性包括whensteup, call, teardown三个值、nodeid(测试用例的名字)、outcome(用例的执行结果passed,failed)
report = outcome.get_result()
report.description = ""
extra = getattr(report, "extra", [])
if report.when == "call" or report.when == "setup":
# 将获取到的用例数据的title作为结果表的Description的值
report.description = GLOBAL_VARS.get("title", "")
# 报错截图添加到报告
xfail = hasattr(report, "wasxfail")
if (report.skipped and xfail) or (report.failed and not xfail):
# 定义截图的文件名
file_name = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + ".png"
# 进行截图操作
GLOBAL_VARS.get("driver").save_screenshot(os.path.join(IMG_DIR, file_name))
# 如果存在截图就将截图以html形式插入到报告中
# 由于img里面必须写相对路径因此需要对IMG_DIR进行处理
if "\\" in IMG_DIR:
image_name = IMG_DIR.split("\\")[-1]
else:
image_name = IMG_DIR.split("/")[-1]
image_path = os.path.join(f"{os.path.join('..', image_name)}", file_name)
image_path = image_path.replace("\\", "/") # html标签中需要使用/
html = f'<div class="image"><img src="{image_path}" onclick="window.open(this.src)"/></div>'
extra.append(pytest_html.extras.html(html))
report.extra = extra
# ------------------------------------- END: 报告处理 ---------------------------------------#