Pytest+Allure+Selenuim+异常截屏+Allure日志

环境构建

环境构建参照

异常截屏

需要使用conftest.py文件,conftest.py需要存在在测试目录中,文件名不能变更,可以根据模块创建层级嵌套。具体参照pytest的官方文档。

  1. 截屏代码
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
  1. conftest.py中捕获异常代码
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
  1. webDriver注入代码

创建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()
  1. Demo
    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日志

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("异常")

效果图
Pytest+Allure+Selenuim+异常截屏+Allure日志_第1张图片

你可能感兴趣的:(自动化测试)