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

相关文章

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

PowerShell中15个提升运维效率关键命令实战指南

《PowerShell中15个提升运维效率关键命令实战指南》作为网络安全专业人员的必备技能,PowerShell在系统管理、日志分析、威胁检测和自动化响应方面展现出强大能力,下面我们就来看看15个提升... 目录一、PowerShell在网络安全中的战略价值二、网络安全关键场景命令实战1. 系统安全基线核查

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

Golang如何用gorm实现分页的功能

《Golang如何用gorm实现分页的功能》:本文主要介绍Golang如何用gorm实现分页的功能方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景go库下载初始化数据【1】建表【2】插入数据【3】查看数据4、代码示例【1】gorm结构体定义【2】分页结构体