欢迎光临
我们一直在努力

使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 41--自定义定制化展示 Allure 测试报告内容

测试学习记录,仅供参考!

自定义定制化展示 Allure 测试报告内容

allure.attach:添加附加信息

在Allure测试报告中,有时候需要添加一些附加信息,例如日志、截图等,以便更好地理解测试结果。pytest-Allure提供了allure.attach函数,可以方便地添加这些附加信息。

allure.attach

allure.attach用于在测试报告中添加附件,补充测试结果。附件格式可以是txt、jpg等,附件内容通常是测试数据、截图等。

allure.attach提供了两种方法:allure.attach(),allure.attach.file()

allure.attach()

作用:在测试报告中生成指定内容、名称、类型的附件

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

参数说明:

  • body,需要显示的内容,也可以理解为写入附件的内容
  • name,附件名称
  • attachment_type,附件类型,如csv、jpg、html 等,由allure.attachment_type提供
  • extension:附件扩展名,不常用
  • allure.attach.file()

    作用:向测试用例中上传附件

    语法:allure.attach.file(source, name=None, attachment_type=None, extension=None)

    参数说明:source为文件路径,其他参数与allure.attach()参数一致。

    在UI自动化测试中,会经常用到这个方法来上传用例执行的截图。

    定制显示报告内容

    添加显示更加详细的allure测试报告的内容;

    1、 优化项目根目录 pageObject 软件包 other 目录下 file_upload_page.py 文件;

            1)、引入 import allure 包(模块/第三方库)

            2)、引入之后在合适的操作步骤中添加调用 allure.attach() 方法

            3)、allure.attach(self.url, '打开测试页面', attachment_type=allure.attachment_type.TEXT)

                    第一个参数:传入要显示的内容;第二个参数:显示的标题;第三个参数:传显示的类型

            4)、根据实际场景按需自行添加

            5)、在 allure.attach() 里面调用截图的方法即可实现在报告中增加显示一个截图功能;之前在项目根目录 util_tools软件包目录basePage.py公共类方法中已经封装好了一个现成的 def screenshots(self, image_name): 截图方法;测试一下看看有木有效果;

            6)、allure.attach(self.screenshots('files'), '文件上传截屏', achment_type=allure.attachment_type.PNG)

                    第一个参数: self.screenshots('files') 调用self.screenshots()里面传入一个文件名

                    第二个参数: 要显示的标题

                    第三个参数: attachment_type=allure.attachment_type.PNG 要保存的图片类型(根据实际需要选择)

    # 导包
    from selenium.webdriver.common.by import By
    from util_tools.basePage import BasePage
    from time import sleep
    import allure

    class FilesUploadPage(BasePage):
    """文件上传"""
    # 外网地址–网络不稳定(建议隔一段时间再访问测试)
    url = 'https://www.leafground.com/file.xhtml'
    # 文件选择
    files_input = (By.XPATH, '//*[@id="j_idt88:j_idt89_input"]')
    # 断言结果
    assert_result = (By.XPATH, '//*[@id="j_idt88:j_idt89"]/span[2]')

    # 操作方法
    def files_upload(self):
    self.open_url(self.url)
    # 第一个参数:传入显示的内容;第二个参数:显示的标题;第三个参数:传显示的类型
    allure.attach(self.url, '打开测试页面', attachment_type=allure.attachment_type.TEXT)
    # 设置要上传的文件路径(自行设置,若写到项目文件中可使用相对路径)–例如:固定的绝对路径(桌面文件)–前面加 r 防止被转义
    file_path = r'C:\\Users\\Administrator\\Desktop\\文件上传.txt'
    allure.attach(file_path, '上传文件', attachment_type=allure.attachment_type.TEXT)
    # 上传文件
    self.send_keys(self.files_input, file_path)
    sleep(3)
    allure.attach(self.screenshots('files'), '文件上传截屏', attachment_type=allure.attachment_type.PNG)

    2、单独运行这个“文件上传”页面类对应的测试类(命令行运行或更改配置文件);

            运行时有报错,再结合显示的“裂图”(图片打不开)说明截图不能这么使用;

    3、详细查看 def screenshots(self, image_name) 方法后发现这个截图方法是要把一个文件保存到目标文件路径中的,截图图片已经固定保存相对应的文件中去了,不符合需要的结果;需要的是把截图结果放到报告中,所以需要再封装一个适用的方法。

    实现步骤页面截图

    添加显示更加详细的allure测试报告的内容,可以给每一个测试步骤添加一个截图,有截图就能追溯到测试结果、测试过程等;

    封装方法

    4、 首先在项目根目录 util_tools 软件包下 basePage.py 文件中封装一个新的截取图片方法;

            1)、定义一个 def screenshots_png(self): 方法:保存为 PNG 图片格式,这里就不传文件名了;

            2)、self.__driver:调用 .点 self.__driver 浏览器对象;

            3)、self.__driver.get_screenshot_as_png:再调用 .get_screenshot_as_png 接收并保存为 png 格式的;

            4)、self.__driver.get_screenshot_as_png():带上 () 小括号,调用这个方法;

            5)、return self.__driver.get_screenshot_as_png():务必要把这个截图返回,return 一下。

    def screenshots_png(self):
    """
    页面截屏,保存为PNG格式
    :return:
    """
    return self.__driver.get_screenshot_as_png()

    5、完整的 basePage.py 文件代码;

    # 导包
    from pyxnat.core.uriutil import file_path
    from selenium import webdriver
    from selenium.common import NoSuchElementException, TimeoutException
    from selenium.webdriver.common.by import By
    from time import sleep
    from selenium.webdriver.support import expected_conditions as ec
    from selenium.webdriver.support.wait import WebDriverWait
    from config import setting
    from util_tools.logs_util.recordlog import logs
    from selenium.webdriver.common.action_chains import ActionChains
    from selenium.webdriver.common.keys import Keys
    from datetime import datetime
    import pytesseract
    from PIL import Image
    from selenium.webdriver.support.ui import Select
    from util_tools.handle_data.configParse import ConfigParse

    class BasePage(object):

    def __init__(self, driver):
    self.__driver = driver
    self.__wait = WebDriverWait(self.__driver, setting.WAIT_TIME)
    self.conf = ConfigParse()

    def window_max(self):
    self.__driver.maximize_window()

    def window_full(self):
    self.__driver.fullscreen_window()

    def screenshot(self):
    self.__driver.get_screenshot_as_png()

    def open_url(self, url):
    if url.startswith('http') or url.startswith('https'):
    self.__driver.get(url)
    logs.info(f'打开页面:{url}')
    else:
    new_url = self.conf.get_host('host') + url
    self.__driver.get(new_url)
    logs.info(f'打开页面:{new_url}')

    def get_tag_text(self, locator: tuple):
    try:
    element = self.location_element(*locator)
    element_text = element.text
    logs.info(f'获取标签文本内容:{element_text}')
    return element_text
    except Exception as e:
    logs.error(f'获取标签文本内容出现异常,原因为:{str(e)}')

    @property
    def current_url(self):
    return self.__driver.current_url

    @property
    def title(self):
    return self.__driver.title

    def refresh(self):
    self.__driver.refresh()

    @property
    def switch_to(self):
    return self.__driver.switch_to

    def iframe(self, frame):
    try:
    self.switch_to.frame(frame)
    logs.info(f'切换到{frame}–iframe内部框架中')
    except:
    logs.error('切换到iframe框架失败!')

    def switch_to_new_tab(self):
    try:
    original_window = self.__driver.window_handles[0]
    all_window = self.__driver.window_handles
    new_window = None
    for window in all_window:
    if window != original_window:
    new_window = window
    break
    if new_window:
    # self.__driver.switch_to.window(new_window)
    self.switch_to.window(new_window)
    logs.info('成功切换到新标签页')
    except TimeoutException:
    logs.error('等待新标签页打开超时。')
    except NoSuchElementException:
    logs.error('未找到新标签页句柄。')
    except Exception as e:
    logs.error(f'切换窗口时发生异常:{str(e)}')

    def exit_iframe(self):
    self.switch_to.default_content()

    @property
    def alert(self):
    return self.__wait.until(ec.alert_is_present())

    def alert_confirm(self):
    self.alert.accept()

    def alert_cancel(self):
    """点击alert弹框中的取消操作"""
    self.alert.dismiss()

    def location_element(self, by, value):
    try:
    element = self.__wait.until(ec.presence_of_element_located((by, value)))
    logs.info(f"找到元素:{by}={value}")
    return element
    except Exception as e:
    logs.error(f"未找到元素:{by}={value}")
    raise e

    def location_elements(self, by, value):
    try:
    self.__wait.until(ec.presence_of_all_elements_located((by, value)))
    elements = self.__driver.find_elements(by, value)
    logs.info(f"找到元素列表:{by}={value}")
    return elements
    except Exception as e:
    logs.error(f"未找到元素列表:{by}={value}")
    raise e

    def click(self, locator: tuple, force=False):
    try:
    element = self.location_element(*locator)
    if not force:
    self.__driver.execute_script("arguments[0].click()", element)
    else:
    self.__driver.execute_script("arguments[0].click({force:true})", element)
    logs.info(f"元素被点击:{locator}")
    except NoSuchElementException as e:
    logs.error(f"元素无法定位:{e}")
    raise e

    def send_keys(self, locator: tuple, data):
    try:
    element = self.location_element(*locator)
    element.send_keys(data)
    logs.info(f"元素被输入内容:{locator},输入的内容为:{data}")
    except NoSuchElementException as e:
    logs.error(f"元素无法定位:{e}")
    raise e

    def selects(self, locator: tuple, index):
    try:
    select = Select(self.location_element(*locator))
    select.select_by_index(index)
    logs.info(f'选择第{index}个数据')
    except NoSuchElementException as e:
    logs.error(f'元素无法定位:{e}')
    raise e

    def enter(self):
    try:
    ActionChains(self.__driver).send_keys(Keys.ENTER).perform()
    logs.info("按下回车键")
    except NoSuchElementException as e:
    logs.error(f"元素无法定位:{e}")
    raise e

    def right_click(self, locator: tuple):
    try:
    element = self.location_element(*locator)
    ActionChains(driver).context_click(element).perform()
    logs.info("执行鼠标右键点击操作")
    except NoSuchElementException as e:
    logs.error(f"元素无法定位:{e}")
    raise e

    def double_click(self, locator: tuple):
    try:
    element = self.location_element(*locator)
    ActionChains(driver).double_click(element).perform()
    logs.info("执行鼠标双击操作")
    except NoSuchElementException as e:
    logs.error(f"元素无法定位:{e}")
    raise e

    def screenshots(self, image_name):
    import os
    current_time = datetime.now().strftime("%Y%m%d%H%M%S")
    file_name = f"{image_name}-{current_time}.png"
    file_path = os.path.join(setting.FILE_PATH.get('screenshot'), file_name)
    self.__driver.get_screenshot_as_file(file_path)

    def screenshots_png(self):
    return self.__driver.get_screenshot_as_png()

    def clear(self, locator: tuple):
    try:
    element = self.location_element(*locator)
    element.clear()
    logs.info("清空文本")
    except NoSuchElementException as e:
    logs.error(f"元素无法定位:{e}")
    raise e

    def ocr_captcha(self, locator: tuple):
    captcha_element = self.location_element(*locator)
    captcha_path = setting.FILE_PATH['screenshot'] + '/captcha.png'
    captcha_element.screenshot(captcha_path)
    captcha_image = Image.open(captcha_path)
    try:
    captcha_text = pytesseract.image_to_string(captcha_image)
    logs.info(f"识别到的验证码为:{captcha_text}")
    return captcha_text
    except pytesseract.pytesseract.TesseractNotFoundError:
    logs.error("找不到tesseract,这是因为pytesseract模块依赖于TesseractOCR引擎来进行图像识别!")

    def is_element_present(self, locator: tuple):
    try:
    self.__wait.until(ec.presence_of_element_located(*locator))
    return True
    except:
    return False

    def assert_is_element_present(self, locator: tuple):
    try:
    element = self.__driver.find_element(*locator)
    assert element.is_displayed(), '元素不存在'
    except NoSuchElementException as e:
    logs.error(f'元素未找到:{e}')
    raise AssertionError('元素不存在')

    def assert_element_not_visible(self, locator: tuple):
    try:
    self.__wait.until(ec.invisibility_of_element_located(locator))
    except TimeoutException:
    logs.error('元素可见')

    def assert_title(self, expect_title):
    assert expect_title in self.title

    # 测试调试
    if __name__ == '__main__':
    driver = webdriver.Edge()
    bros = BasePage(driver)
    bros.open_url('https://www.leafground.com/alert.xhtml')
    print(bros.current_url)
    print(bros.title)
    sleep(3)

    使用

    页面类通过 allure.acctch()调用即可

    6、优化 file_upload_page.py 文件;根据实际需求场景自定义的去添加要显示的内容;

    # 导包
    from selenium.webdriver.common.by import By
    from util_tools.basePage import BasePage
    from time import sleep
    import allure

    class FilesUploadPage(BasePage):
    """文件上传"""
    # 外网地址–网络不稳定(建议隔一段时间再访问测试)
    url = 'https://www.leafground.com/file.xhtml'
    # 文件选择
    files_input = (By.XPATH, '//*[@id="j_idt88:j_idt89_input"]')
    # 断言结果
    assert_result = (By.XPATH, '//*[@id="j_idt88:j_idt89"]/span[2]')

    # 操作方法
    def files_upload(self):
    self.open_url(self.url)
    # 第一个参数:传入显示的内容;第二个参数:显示的标题;第三个参数:传显示的类型
    allure.attach(self.url, '打开测试页面', attachment_type=allure.attachment_type.TEXT)
    # 设置要上传的文件路径(自行设置,若写到项目文件中可使用相对路径)–例如:固定的绝对路径(桌面文件)–前面加 r 防止被转义
    file_path = r'C:\\Users\\Administrator\\Desktop\\文件上传.txt'
    allure.attach(file_path, '上传文件', attachment_type=allure.attachment_type.TEXT)
    # 上传文件
    self.send_keys(self.files_input, file_path)
    sleep(3)
    # 调用新封装的截图方法把截图添加到测试报告中
    allure.attach(self.screenshots_png(), '文件上传截屏', attachment_type=allure.attachment_type.PNG)

    7、单独运行查看,能够实现截屏功能,每条测试用例里面的测试步骤亦比较清晰明了;

    8、用同样的方式去套用完善其他模块(例如登录、注册模块等–自行设置)

    from selenium.webdriver.common.by import By
    from util_tools.basePage import BasePage
    import allure

    # 登录页面类
    class LoginPage(BasePage):
    # url = 'http://localhost:8088/ecshop/user.php'
    url = '/user.php'
    # 用户名
    username = (By.NAME, 'username')
    # 密码
    password = (By.NAME, 'password')
    # 登录按钮
    submit = (By.NAME, 'submit')
    # 断言结果
    assert_result = (By.XPATH, '//*[@id="ECS_MEMBERZONE"]/font/font')

    # 登录操作
    def login(self, user_name, pass_word):
    # 打开网址
    self.open_url(self.url)
    # 第一个参数:传入显示的内容;第二个参数:显示的标题;第三个参数:传显示的类型
    allure.attach(self.url, '打开登录测试页面', attachment_type=allure.attachment_type.TEXT)
    # 输入用户名
    self.send_keys(self.username, user_name)
    # 输入密码
    self.send_keys(self.password, pass_word)
    # 点击登录按钮
    self.click(self.submit)
    allure.attach(self.screenshots_png(), f'输入账户:{user_name}, 密码:{pass_word}, 内容截屏', attachment_type=allure.attachment_type.PNG)

    9、若是觉得 allure.attach() 方法会去频繁调用的话可以考虑封装到公共方法中统一去调用;

            封装完之后调用,再传一个需要显示的内容就行了(烦请自行封装);

    10、测试运作查看;

    未完待续。。。

    赞(0)
    未经允许不得转载:171主机测评 » 使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 41--自定义定制化展示 Allure 测试报告内容
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址