Bootstrap

pytest在conftest.py中实现用例执行失败进行截图并附到allure测试报告

conftest.py文件简介

conftest.py文件用于定义共享设置、夹具和钩子函数。
可以跨.py文件调用,有多个.py文件调用时,可让conftest.py只调用了一次fixture,或调用多次fixture;
conftest.py与运行的用例要在同一个pakage下,并且有__init__.py文件;
不需要import导入conftest.py,pytest用例会自动识别该文件,放到项目的根目录下就可以全局目录调用了。如果放到某个package下,那就在package内有效。可有多个conftest.py,遵循局部优先原则。
conftest.py配置脚本名称是固定的,不能改名称;
conftest.py文件不能被其他文件导入;
所有同目录测试文件运行前都会执行conftest.py文件;

在allure测试报告中添加内容

allure.attach(body, name=None, attachment_type=None, extension=None)

body为具体内容
name为标题
attachment_type为添加内容的类型,如:allure.attachment_type.TEXT、allure.attachment_type.PNG

在conftest.py文件中实现用例执行失败进行截图并附到allure报告中

pytest_runtest_makereport

首先要了解下pytest_runtest_makereport,pytest_runtest_makereport是pytest的钩子函数,可以返回每个用例每个阶段的执行结果,包括setup、call、teardown,call即为test_开头的具体的用例。
pytest_runtest_makereport分别会在前置步骤、测试用例和后置步骤执行完成后被调用。
pytest_runtest_makereport函数需要放在conftest.py文件中,可以使用outcome = yield来获取执行结果,outcom取值为passed表示执行通过,outcome取值为Failed表示执行失败。outcome.get_result() 用来获取测试报告。

具体实现方法

具体实现代码比较简单,如下:

import allure
import pytest
import config.globals as globals

@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
    '''获取用例执行结果,如果执行失败,则将失败时的截图添加到allure报告中'''
    # 获取调用结果
    outcome = yield

    # 获取测试报告
    rep = outcome.get_result()

    if rep.passed == False:
        # 前后置也有可能运行失败,失败时也截图到报告中
        if globals.driver is not None:
            pic = globals.driver.get_screenshot_as_png()
            allure.attach(pic, "失败用例的截图", allure.attachment_type.PNG)
    elif rep.passed == True and rep.when == "call":
    	# 只在用例执行阶段对成功的用例进行截图,前后置阶段忽略
        if globals.driver is not None:
            pic = globals.driver.get_screenshot_as_png()
            allure.attach(pic, "成功用例的截图", allure.attachment_type.PNG)

这里的dirver是在globals.py文件中单独定义的一个变量。相当于设置了一个全局变量,每次basepage被实例化的时候,都会给这个变量赋值。basepage是对selenium基本操作封装的一个类。这样,conftest.py文件中的dirver就和用例执行时的driver是同一个,保证是对同一个页面进行操作。
globals.py文件内容如下:

# -*- coding: utf-8 -*-#

driver = None

basepage类的构造函数如下:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.edge.options import Options as edgeOptions
from selenium.webdriver.edge.service import Service as edgeService
import config.globals as globals

class basepage():
    def __init__(self, browser_name='chrome'):
        self.browser_name = browser_name
        
        if self.browser_name == 'chrome':
            chromedriver_path = '谷歌浏览器的驱动文件路径'
            service = ChromeService(executable_path=chromedriver_path)
            options = ChromeOptions()
            options.add_experimental_option('detach', True)
            self.driver = webdriver.Chrome(service=service, options=options)
        elif self.browser_name == 'edge':
            chromedriver_path = 'edge浏览器的驱动文件路径'
            service = edgeService(executable_path=chromedriver_path)
            options = edgeOptions()
            options.add_experimental_option('detach', True)
            self.driver = webdriver.Edge(service=service, options=options)

        # 在此处给全局变量driver赋值
        globals.driver = self.driver
;