环境构建参照
需要使用conftest.py文件,conftest.py需要存在在测试目录中,文件名不能变更,可以根据模块创建层级嵌套。具体参照pytest的官方文档。
from selenium.webdriver.remote.webdriver import WebDriver
import allure
def _capture_screenshot(driver: WebDriver):
fileName = config.tmpPath + '/' + str(uuid.uuid1()) + '.png'
driver.get_screenshot_as_file(fileName)
return fileName
def save_capture(driver: WebDriver, name: str):
fileName = _capture_screenshot(driver)
if os.path.exists(fileName):
allure.attach.file(fileName,
attachment_type=allure.attachment_type.PNG, name=name)
pass
pass
from selenium.webdriver.remote.webdriver import WebDriver
import pytest
@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):
"""
Extends the PyTest Plugin to take and embed screenshot in html report, whenever test fails.
:param item:
"""
outcome = yield
report = outcome.get_result()
extra = getattr(report, 'extra', [])
if report.when == 'call' or report.when == "setup":
xfail = hasattr(report, 'wasxfail')
#判断用例是否失败或者xfail跳过的测试
if (report.skipped and xfail) or (report.failed and not xfail):
#获取测试用例代码中webDriver参数来获取浏览器进行抓屏
for i in item.funcargs:
if isinstance(item.funcargs[i], WebDriver):
#截图
basic.save_capture(item.funcargs[i], "异常截图")
pass
pass
pass
report.extra = extra
创建webDriver代码
#PC浏览器
def create_driver(options=Options()):
# type: () -> webdriver.Remote
if config.arguments and len(config.arguments) > 0:
for arg in config.arguments:
options.add_argument(arg)
pass
pass
driver = None
if config.runMode == config.RunModeType.remote:
driver = webdriver.Remote(command_executor=config.remoteUrl, options=options)
pass
else:
driver = webdriver.Chrome(options=options)
pass
driver.set_page_load_timeout(config.timeOut)
driver.set_script_timeout(config.timeOut)
driver.set_window_size(1366, 768)
return driver
pass
#手机浏览器
def create_driver_mobile():
# type: () -> webdriver.Remote
options = Options()
options.add_experimental_option('mobileEmulation', {"deviceName": "iPhone X"})
return create_driver(options)
注入代码
@pytest.fixture(scope='function')
def browser():#功能级别注入,每个功能会调用以下这个代码生成pc端浏览器对象
driver = basic.create_driver()
yield driver
driver.quit()
pass
@pytest.fixture(scope='function')
def mobileBrowser():#手机端浏览器对象注入
driver = basic.create_driver_mobile()
yield driver
driver.quit()
def test_login_pc(self, browser):
"""
测试正常登录Demo
:param browser:
:return:
"""
#无关代码主要是用来打开个页面截图用
loginPage = LoginPage(browser)
loginPage.login(envs.user1["userName"], envs.user1["password"])
#测试PC截图
assert False
pass
def test_login_mobile(self, mobileBrowser, log):
"""
测试手机端登录Demo
:param mobileBrowser:
:param log:
:return:
"""
#无关代码主要是用来打开个页面截图用
loginPage = LoginPage(mobileBrowser)
loginPage.login(envs.user1["userName"], envs.user1["password"])
log.info("测试完成", driver=mobileBrowser)
#测试手机截图
assert False
pass
def test_two_browser(self, browser, mobileBrowser):
"""
测试双浏览器Demo
:param browser:
:param mobileBrowser:
:return:
"""
#无关代码主要是用来打开个页面截图用
pcLoginPage = pc_loginPage(browser)
mobile_loginPage = m_loginPage(mobileBrowser)
pcLoginPage.login(envs.user1["userName"], envs.user1["password"])
mobile_loginPage.login(envs.user1["userName"], envs.user1["password"])
#测试双浏览器截图
assert False
pass
allure中输出日志有两种方法,一种是使用print输出,另一种是使用logging模块来输出日志。但是两种日志都无法与截图结合在一起,因为他们是分开显示的。
所以我尝试使用allure的step来来输出日志。但是单纯的输出step加上截图需要写太多的框架代码,so 代码如下:
新写一个logger类继承logging.Logger重写_log方法
import logging
import sys
import allure
from selenium.webdriver.remote.webdriver import WebDriver
from common import basic
class AllureLogger(logging.Logger):
formatter = None
def __init__(self, name):
super().__init__(name)
self.formatter = logging.Formatter(fmt='%(asctime)s-%(levelname)s:\t %(message)s',
datefmt='%H:%M:%S')
def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False, stacklevel=1,
driver: WebDriver = False):
"""
Low-level logging routine which creates a LogRecord and then calls
all the handlers of this logger to handle the record.
"""
sinfo = None
if logging._srcfile:
# IronPython doesn't track Python frames, so findCaller raises an
# exception on some versions of IronPython. We trap it here so that
# IronPython can use logging.
try:
fn, lno, func, sinfo = self.findCaller(stack_info, stacklevel)
except ValueError: # pragma: no cover
fn, lno, func = "(unknown file)", 0, "(unknown function)"
else: # pragma: no cover
fn, lno, func = "(unknown file)", 0, "(unknown function)"
record = self.makeRecord(self.name, level, fn, lno, msg, args,
None, func, None, None)
title = self.formatter.format(record)
with allure.step(title):#输出step
if driver:#如果参数中有webDriver对象则进行截屏
basic.save_capture(driver, "快照")
pass
if exc_info:
if isinstance(exc_info, BaseException):
exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
elif not isinstance(exc_info, tuple):
exc_info = sys.exc_info()
record = self.makeRecord(self.name, level, fn, lno, msg, args,
exc_info, func, extra, sinfo)
if exc_info:#如果执行异常,把堆栈信息写入allure attach文件
allure.attach(self.formatter.format(record), "堆栈", allure.attachment_type.TEXT)
pass
self.handle(record)
pass
pass
pass
设置默认日志类
import logging
logging.setLoggerClass(AllureLogger)
Demo
log = logging.getLogger(self.__class__.__module__)
log.debug("输入用户名")
log.info("点击密码输入框")
log.info("等待页面跳转", driver=self.driver)#附带截图的日志
log.exception("异常")