Playwright 和 Pytest 之 自动化用例自愈功能实战

2024-04-30 13:52

本文主要是介绍Playwright 和 Pytest 之 自动化用例自愈功能实战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

当使用 Playwright 的 Locator 进行元素定位,并结合 pytest 编写自动化测试时,可以利用 pytest 的功能和 Playwright 提供的定位方法来实现自动化修复。下面我将详细展示如何实现这些功能:

自动化修复

在测试过程中捕获失败并尝试自动修复问题。我们将使用 Playwright 的 Locator 来定位元素,并在失败时重新定位更新元素。

base.py

# -*- coding: utf-8 -*-
# @Author  : blues_C
# @File    : base.py
# @Desc:import re
from utils.logger import log
from playwright.sync_api import Page, expect, Locatorclass BasePage:def __init__(self, page: Page):self.page = pagedef locator(self, selector: str) -> Locator:"""查找并返回元素"""element = self.page.locator(selector)if not element.is_visible():self.auto_repair()return elementdef click(self, selector: str):self.locator(selector).click()def fill(self, selector: str, input_value: str):self.locator(selector).fill(input_value)def auto_repair(self, scope_selector: str = "body",selector: str = "input, button, a, select, textarea, div, span, img, iframe, label, svg",filename="login_element.py"):page_title = self.page.title()scope = self.page.locator(scope_selector)elements = scope.locator(selector).all()log.info(f"自愈元素: {selector} (共 {len(elements)} 个)")# 检查文件是否存在if os.path.exists(filename):# 读取现有文件内容,以便检查变量名with open(filename, "r") as file:lines = file.readlines()existing_variables = set()# 获取现有的变量名for line in lines:if "=" in line:variable_name = line.split("=")[0].strip()existing_variables.add(variable_name)# 打开文件,准备写入新内容with open(filename, "w") as file:file.write(f"# Existing variables from {page_title}\n\n")for element in elements:element_info = f"element='{element}', "start_index = element_info.find("selector=")if start_index != -1:selector_str = element_info[start_index + len("selector='"):]end_index = selector_str.find("'")if end_index != -1:selector_content = selector_str[:end_index]# 获取各个属性text = element.inner_text()value = element.get_attribute('value')element_id = element.get_attribute('id')element_class = element.get_attribute('class')element_name = element.get_attribute('name')element_type = element.get_attribute('type')element_placeholder = element.get_attribute('placeholder')# 检查属性是否为 None,并记录非 None 的属性log_info = f"element='{selector_content}', "if text != '':log_info += f"text='{text}'  "if value != '' and value is not None:log_info += f"[value='{value}']  "if element_id is not None:log_info += f"#{element_id}  "if element_class is not None:log_info += f"[class='{element_class}']  "if element_name is not None:log_info += f"[name='{element_name}']  "if element_type is not None:log_info += f"[type='{element_type}']  "if element_placeholder is not None:log_info += f"[placeholder='{element_placeholder}']"# 打印日志信息log.info(log_info)# 如果变量名已存在,替换现有的定义行if variable_name in existing_variables:file.write(f"# {log_info} (replaced)\n")if element.get_attribute('name') is not None:variable_name = element.get_attribute('name')variable_type = selector_contentfile.write(f"{variable_name} = '{variable_type}'\n\n")existing_variables.add(variable_name)elif element.get_attribute('type') is not None:variable_name = element.get_attribute('type')variable_type = selector_contentfile.write(f"{variable_name} = '{variable_type}'\n\n")existing_variables.add(variable_name)else:variable_type = selector_contentfile.write(f"'{variable_type}'\n\n")existing_variables.add(variable_name)else:# 如果文件不存在,则创建新文件并写入内容with open(filename, "w") as file:file.write(f"# {page_title}\n")for element in elements:element_info = f"element='{element}', "start_index = element_info.find("selector=")if start_index != -1:selector_str = element_info[start_index + len("selector='"):]end_index = selector_str.find("'")if end_index != -1:selector_content = selector_str[:end_index]text = element.inner_text()value = element.get_attribute('value')element_id = element.get_attribute('id')element_class = element.get_attribute('class')element_name = element.get_attribute('name')element_type = element.get_attribute('type')element_placeholder = element.get_attribute('placeholder')info = f"element='{selector_content}', "if text != '':info += f"text='{text}'  "if value != '' and value is not None:info += f"[value='{value}']  "if element_id is not None:info += f"#{element_id}  "if element_class is not None:info += f"[class='{element_class}']  "if element_name is not None:info += f"[name='{element_name}']  "if element_type is not None:info += f"[type='{element_type}']  "if element_placeholder is not None:info += f"[placeholder='{element_placeholder}']"log.info(info)file.write(f"# {info}\n")if element.get_attribute('name') is not None:variable_name = element.get_attribute('name')variable_type = selector_contentfile.write(f"{variable_name} = '{variable_type}'\n\n")elif element.get_attribute('type') is not None:variable_name = element.get_attribute('type')variable_type = selector_contentfile.write(f"{variable_name} = '{variable_type}'\n\n")else:variable_type = selector_contentfile.write(f"'{variable_type}'\n\n")

conftest.py

import pytest
from playwright.sync_api import sync_playwright@pytest.fixture(scope='session')
def browser():with sync_playwright() as p:browser = p.chromium.launch()yield browserbrowser.close()

test_cases.py

import pytest
from common.base import BasePage
from playwright.sync_api import sync_playwrightdef test_auto_repair(browser):page = browser.new_page()page.goto('https://example.com')try:# 运行测试步骤BasePage(page).fill(login_element.username, 'username')BasePage(page).fill(login_element.password, 'password')BasePage(page).click(login_element.login)except Exception as e:pytest.fail(f'Test failed: {e}')BasePage(page).fill(login_element.username, 'username')BasePage(page).fill(login_element.password, 'password')BasePage(page).click(login_element.login)

login_element.py 示例:

# 登录到 standard
# element='form >> input,button >> nth=0', #username  [class='form-control']  [name='username']  [type='text']  
username = 'form >> input,button >> nth=0'# element='form >> input,button >> nth=1', #password  [class='form-control']  [name='password']  [type='password']  
password = 'form >> input,button >> nth=1'# element='form >> input,button >> nth=2', #id-hidden-input  [name='credentialId']  [type='hidden']  
credentialId = 'form >> input,button >> nth=2'# element='form >> input,button >> nth=3', [value='登录']  #kc-login  [class='btn btn-primary btn-block btn-lg']  [name='login']  [type='submit']  
login = 'form >> input,button >> nth=3'

总结

在上面的示例中:
pytest.fixture(scope=‘session’) 是一个 pytest fixture,用于在测试函数运行前后启动和关闭浏览器。
page.locator(‘selector’) 定位页面上的元素,如果元素不可见或定位失败,则重新定位更新元素。
如果测试步骤失败(例如,元素点击失败),则使用 pytest.fail() 来标记测试失败。

这篇关于Playwright 和 Pytest 之 自动化用例自愈功能实战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/949041

相关文章

Python在二进制文件中进行数据搜索的实战指南

《Python在二进制文件中进行数据搜索的实战指南》在二进制文件中搜索特定数据是编程中常见的任务,尤其在日志分析、程序调试和二进制数据处理中尤为重要,下面我们就来看看如何使用Python实现这一功能吧... 目录简介1. 二进制文件搜索概述2. python二进制模式文件读取(rb)2.1 二进制模式与文本

Django调用外部Python程序的完整项目实战

《Django调用外部Python程序的完整项目实战》Django是一个强大的PythonWeb框架,它的设计理念简洁优雅,:本文主要介绍Django调用外部Python程序的完整项目实战,文中通... 目录一、为什么 Django 需要调用外部 python 程序二、三种常见的调用方式方式 1:直接 im

springboot+redis实现订单过期(超时取消)功能的方法详解

《springboot+redis实现订单过期(超时取消)功能的方法详解》在SpringBoot中使用Redis实现订单过期(超时取消)功能,有多种成熟方案,本文为大家整理了几个详细方法,文中的示例代... 目录一、Redis键过期回调方案(推荐)1. 配置Redis监听器2. 监听键过期事件3. Redi

C#实现将XML数据自动化地写入Excel文件

《C#实现将XML数据自动化地写入Excel文件》在现代企业级应用中,数据处理与报表生成是核心环节,本文将深入探讨如何利用C#和一款优秀的库,将XML数据自动化地写入Excel文件,有需要的小伙伴可以... 目录理解XML数据结构与Excel的对应关系引入高效工具:使用Spire.XLS for .NETC

Java利用Spire.XLS for Java自动化设置Excel的文档属性

《Java利用Spire.XLSforJava自动化设置Excel的文档属性》一个专业的Excel文件,其文档属性往往能大大提升文件的可管理性和可检索性,下面我们就来看看Java如何使用Spire... 目录Spire.XLS for Java 库介绍与安装Java 设置内置的 Excel 文档属性Java

SpringBoot整合 Quartz实现定时推送实战指南

《SpringBoot整合Quartz实现定时推送实战指南》文章介绍了SpringBoot中使用Quartz动态定时任务和任务持久化实现多条不确定结束时间并提前N分钟推送的方案,本文结合实例代码给大... 目录前言一、Quartz 是什么?1、核心定位:解决什么问题?2、Quartz 核心组件二、使用步骤1

Python自动化提取多个Word文档的文本

《Python自动化提取多个Word文档的文本》在日常工作和学习中,我们经常需要处理大量的Word文档,本文将深入探讨如何利用Python批量提取Word文档中的文本内容,帮助你解放生产力,感兴趣的小... 目录为什么需要批量提取Word文档文本批量提取Word文本的核心技术与工具安装 Spire.Doc

C#高效实现在Word文档中自动化创建图表的可视化方案

《C#高效实现在Word文档中自动化创建图表的可视化方案》本文将深入探讨如何利用C#,结合一款功能强大的第三方库,实现在Word文档中自动化创建图表,为你的数据呈现和报告生成提供一套实用且高效的解决方... 目录Word文档图表自动化:为什么选择C#?从零开始:C#实现Word文档图表的基本步骤深度优化:C

SpringBoot整合AOP及使用案例实战

《SpringBoot整合AOP及使用案例实战》本文详细介绍了SpringAOP中的切入点表达式,重点讲解了execution表达式的语法和用法,通过案例实战,展示了AOP的基本使用、结合自定义注解以... 目录一、 引入依赖二、切入点表达式详解三、案例实战1. AOP基本使用2. AOP结合自定义注解3.

Qt实现对Word网页的读取功能

《Qt实现对Word网页的读取功能》文章介绍了几种在Qt中实现Word文档(.docx/.doc)读写功能的方法,包括基于QAxObject的COM接口调用、DOCX模板替换及跨平台解决方案,重点讨论... 目录1. 核心实现方式2. 基于QAxObject的COM接口调用(Windows专用)2.1 环境