feat: 优化定位转换器调整框架结构
- 新增 finder.py 重构定位转换器 - 优化 .gitignore 文件 - 其他优化
This commit is contained in:
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Python-generated files
|
||||
__pycache__/
|
||||
*.py[oc]
|
||||
build/
|
||||
dist/
|
||||
wheels/
|
||||
*.egg-info
|
||||
.idea
|
||||
# Virtual environments
|
||||
.venv/
|
||||
data/
|
||||
logs/
|
||||
report
|
||||
screenshot/
|
||||
temp/
|
||||
xlsx/
|
||||
uv.lock
|
||||
@@ -11,7 +11,7 @@
|
||||
"""
|
||||
from time import sleep
|
||||
|
||||
from selenium.webdriver import Chrome
|
||||
from selenium.webdriver import Chrome,Edge
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.remote.webdriver import WebDriver
|
||||
from commons.modules import Browser
|
||||
@@ -28,28 +28,28 @@ class LoginPage(KeyWordDriver):
|
||||
password = '//*[@id="pass"]'
|
||||
login_submit = '//*[@id="root"]/div[1]/div/div/form/div[3]/button'
|
||||
|
||||
# def __init__(self, browser: Browser):
|
||||
# super().__init__(browser)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def __init__(self,driver: WebDriver | None = None):
|
||||
super().__init__(driver)
|
||||
|
||||
def login(self, email, password):
|
||||
self.browser(Browser.EDGE)
|
||||
|
||||
# self.base_url("http://119.91.19.171:40065")
|
||||
self.get(self.url)
|
||||
self.input(1, self.email, email)
|
||||
self.input(By.XPATH, self.password, password)
|
||||
text = self.get_text(By.XPATH, self.email_title)
|
||||
print(text)
|
||||
self.click(By.XPATH, self.login_submit)
|
||||
sleep(10)
|
||||
|
||||
# sleep(10)
|
||||
# input()
|
||||
|
||||
if __name__ == '__main__':
|
||||
from commons.settings import configs
|
||||
|
||||
# _driver =Edge()
|
||||
_email = configs.username
|
||||
_password = configs.password
|
||||
login = LoginPage()
|
||||
# login.browser(Browser.EDGE)
|
||||
login.base_url(configs.base_url)
|
||||
|
||||
login.login(_email, _password)
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
"""
|
||||
@author: CNWei
|
||||
@Software: PyCharm
|
||||
@contact: t6i888@163.com
|
||||
@file: main
|
||||
@date: 2025/4/4 17:52
|
||||
@desc:
|
||||
"""
|
||||
from time import sleep
|
||||
import pytest
|
||||
from selenium.webdriver import Chrome
|
||||
from login_page import LoginPage
|
||||
from commons.modules import Browser
|
||||
|
||||
|
||||
@pytest.mark.parametrize("email, password", [("username", "password"), ("<EMAIL>", "<PASSWORD>")])
|
||||
def test_login(driver, email, password):
|
||||
login = LoginPage()
|
||||
|
||||
login.login(email, password)
|
||||
# sleep(10)
|
||||
|
||||
|
||||
def test_logout_1(login_ok):
|
||||
login = LoginPage()
|
||||
login.browser(Browser.CHROME)
|
||||
login.get("https://www.baidu.com/")
|
||||
print("logout")
|
||||
|
||||
|
||||
# @pytest.mark.usefixtures("login_ok")
|
||||
def test_logout_2():
|
||||
login = LoginPage()
|
||||
login.browser(Browser.CHROME)
|
||||
login.get("https://www.baidu.com/")
|
||||
print("logout")
|
||||
@@ -10,12 +10,12 @@
|
||||
@desc:
|
||||
"""
|
||||
import pytest
|
||||
from selenium.webdriver import Chrome
|
||||
from selenium.webdriver import Chrome,Edge
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def driver():
|
||||
_driver = Chrome()
|
||||
_driver = Edge()
|
||||
yield _driver
|
||||
_driver.quit()
|
||||
|
||||
40
POM/tests/test_login.py
Normal file
40
POM/tests/test_login.py
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
"""
|
||||
@author: CNWei
|
||||
@Software: PyCharm
|
||||
@contact: t6i888@163.com
|
||||
@file: main
|
||||
@date: 2025/4/4 17:52
|
||||
@desc:
|
||||
"""
|
||||
from time import sleep
|
||||
import pytest
|
||||
from selenium.webdriver import Chrome
|
||||
from POM.page.login_page import LoginPage
|
||||
from commons.modules import Browser
|
||||
|
||||
|
||||
@pytest.mark.parametrize("email, password", [("ltcs@ltcs.com", "ltcs2024")])
|
||||
def test_login(driver, email, password):
|
||||
login = LoginPage(driver)
|
||||
|
||||
login.login(email, password)
|
||||
# sleep(10)
|
||||
|
||||
|
||||
def test_logout_1(driver):
|
||||
login = LoginPage(driver)
|
||||
# login.browser(Browser.CHROME)
|
||||
login.get("/questions/10010000000000002")
|
||||
print("logout")
|
||||
sleep(10)
|
||||
#
|
||||
#
|
||||
# # @pytest.mark.usefixtures("login_ok")
|
||||
# def test_logout_2():
|
||||
# login = LoginPage()
|
||||
# login.browser(Browser.CHROME)
|
||||
# login.get("https://www.baidu.com/")
|
||||
# print("logout")
|
||||
@@ -20,7 +20,7 @@ from selenium.webdriver.remote.webdriver import WebDriver
|
||||
from selenium.webdriver.remote.webdriver import WebElement
|
||||
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
from selenium.webdriver.support.expected_conditions import visibility_of_element_located
|
||||
__all__ = ["EC","custom_ec"]
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -97,3 +97,16 @@ def func_4(mark):
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(custom_ec)
|
||||
from selenium.common.exceptions import StaleElementReferenceException
|
||||
|
||||
def luo_ji(locator: Tuple[str, str]):
|
||||
_ = locator
|
||||
|
||||
def _predicate(driver):
|
||||
try:
|
||||
_ = driver
|
||||
raise StaleElementReferenceException()
|
||||
except StaleElementReferenceException:
|
||||
return False
|
||||
|
||||
return _predicate
|
||||
@@ -11,6 +11,7 @@
|
||||
"""
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from time import sleep
|
||||
import secrets # 原生库,用于生成安全的随机数
|
||||
from typing import Optional, Callable, Union, Literal, Any, TypeVar
|
||||
@@ -28,6 +29,8 @@ from commons.custom_expected_condition import EC, custom_ec
|
||||
from commons.modules import Browser, Locator
|
||||
from commons.settings import configs, EXPLICIT_WAIT_TIMEOUT, SCREENSHOT_DIR
|
||||
|
||||
from commons.webdriver_finder import BrowserFinder
|
||||
from utils.finder import by_converter
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
WebDriverOrWebElement = Union[WebDriver, WebElement]
|
||||
@@ -41,51 +44,35 @@ T = TypeVar("T")
|
||||
# 筛选器 Filters
|
||||
# 查找器 finder
|
||||
# 转换器 converter
|
||||
def webdriver_finder(browser: str | Browser = Browser.CHROME) -> WebDriver:
|
||||
match browser:
|
||||
case Browser.CHROME:
|
||||
return Chrome()
|
||||
case Browser.FIREFOX:
|
||||
return Firefox()
|
||||
case Browser.IE:
|
||||
return Ie()
|
||||
case Browser.SAFARI:
|
||||
return Safari()
|
||||
case Browser.EDGE:
|
||||
return Edge()
|
||||
case _:
|
||||
return Chrome() # 默认情况
|
||||
|
||||
|
||||
def by_converter(by_value: str | Locator):
|
||||
try:
|
||||
# 统一处理输入
|
||||
if isinstance(by_value, str):
|
||||
by = Locator(by_value.lower().replace(' ', ''))
|
||||
|
||||
# 创建对应的浏览器实例
|
||||
by = {
|
||||
Locator.ID: By.ID,
|
||||
Locator.NAME: By.NAME,
|
||||
Locator.CLASS: By.CLASS_NAME,
|
||||
Locator.TAG: By.TAG_NAME,
|
||||
Locator.LINK_TEXT: By.LINK_TEXT,
|
||||
Locator.PARTIAL_LINK_TEXT: By.PARTIAL_LINK_TEXT,
|
||||
Locator.CSS: By.CSS_SELECTOR,
|
||||
Locator.XPATH: By.XPATH,
|
||||
}.get(by_value, By.XPATH)
|
||||
return by
|
||||
except ValueError:
|
||||
return By.XPATH
|
||||
# def by_converter(by_value: str | Locator):
|
||||
# try:
|
||||
# # 统一处理输入
|
||||
# if isinstance(by_value, str):
|
||||
# by = Locator(by_value.lower().replace(' ', ''))
|
||||
#
|
||||
# # 创建对应的浏览器实例
|
||||
# by = {
|
||||
# Locator.ID: By.ID,
|
||||
# Locator.NAME: By.NAME,
|
||||
# Locator.CLASS: By.CLASS_NAME,
|
||||
# Locator.TAG: By.TAG_NAME,
|
||||
# Locator.LINK_TEXT: By.LINK_TEXT,
|
||||
# Locator.PARTIAL_LINK_TEXT: By.PARTIAL_LINK_TEXT,
|
||||
# Locator.CSS: By.CSS_SELECTOR,
|
||||
# Locator.XPATH: By.XPATH,
|
||||
# }.get(by_value, By.XPATH)
|
||||
# return by
|
||||
# except ValueError:
|
||||
# return By.XPATH
|
||||
|
||||
|
||||
class KeyWordDriver:
|
||||
class CoreDriver:
|
||||
|
||||
# def __init__(self, browser: str | Browser):
|
||||
# self.driver = self.webdriver_finder(browser)
|
||||
def __init__(self):
|
||||
self.driver: WebDriver | None = None
|
||||
self._url: str | None = None
|
||||
def __init__(self, driver: WebDriver | None = None):
|
||||
self.driver: WebDriver | None = driver
|
||||
self._url: str | None = configs.base_url
|
||||
# self.temp_value = None
|
||||
|
||||
def base_url(self, url: str, *args, **kwargs):
|
||||
@@ -93,28 +80,33 @@ class KeyWordDriver:
|
||||
self._url = url
|
||||
# return url
|
||||
|
||||
def browser(self, browser_name: str | Browser = Browser.CHROME, *args, **kwargs):
|
||||
def browser(self, browser_name: str | Browser = Browser.CHROME, browser_dir: Path | str | None = None,
|
||||
browser_driver: Path | str | None = None, *args, **kwargs):
|
||||
browser_name = Browser(browser_name.lower().replace(' ', '')) if isinstance(browser_name, str) else browser_name
|
||||
match browser_name:
|
||||
case Browser.CHROME:
|
||||
logger.info(f"启动{Browser.CHROME}浏览器")
|
||||
self.driver = Chrome()
|
||||
# return Chrome()
|
||||
case Browser.FIREFOX:
|
||||
logger.info(f"启动{Browser.FIREFOX}浏览器")
|
||||
self.driver = Firefox()
|
||||
case Browser.IE:
|
||||
logger.info(f"启动{Browser.IE}浏览器")
|
||||
self.driver = Ie()
|
||||
case Browser.SAFARI:
|
||||
logger.info(f"启动{Browser.SAFARI}浏览器")
|
||||
self.driver = Safari()
|
||||
case Browser.EDGE:
|
||||
logger.info(f"启动{Browser.EDGE}浏览器")
|
||||
self.driver = Edge()
|
||||
case _:
|
||||
logger.info(f"启动默认浏览器: {Browser.CHROME}")
|
||||
self.driver = Chrome() # 默认情况
|
||||
|
||||
logger.info(f"启动 {browser_name.value} 浏览器")
|
||||
|
||||
self.driver = BrowserFinder(browser_name=browser_name).get_browser_driver(browser_dir, browser_driver)
|
||||
# match browser_name:
|
||||
# case Browser.CHROME:
|
||||
# logger.info(f"启动{Browser.CHROME}浏览器")
|
||||
# self.driver = Chrome()
|
||||
# # return Chrome()
|
||||
# case Browser.FIREFOX:
|
||||
# logger.info(f"启动{Browser.FIREFOX}浏览器")
|
||||
# self.driver = Firefox()
|
||||
# case Browser.IE:
|
||||
# logger.info(f"启动{Browser.IE}浏览器")
|
||||
# self.driver = Ie()
|
||||
# case Browser.SAFARI:
|
||||
# logger.info(f"启动{Browser.SAFARI}浏览器")
|
||||
# self.driver = Safari()
|
||||
# case Browser.EDGE:
|
||||
# logger.info(f"启动{Browser.EDGE}浏览器")
|
||||
# self.driver = Edge()
|
||||
# case _:
|
||||
# logger.info(f"启动默认浏览器: {Browser.CHROME}")
|
||||
# self.driver = Chrome() # 默认情况
|
||||
|
||||
def find_element(self, by: str = By.XPATH, value: Optional[str] = None, *args, **kwargs) -> WebElement:
|
||||
by = by_converter(by)
|
||||
@@ -137,7 +129,7 @@ class KeyWordDriver:
|
||||
|
||||
def explicit_wait(self, method: T, timeout: float = EXPLICIT_WAIT_TIMEOUT, *args, **kwargs):
|
||||
"""
|
||||
显示等待
|
||||
显示等待AttributeError: 'WebDriver' object has no attribute 'send_keys'
|
||||
:param method: 可调用对象名
|
||||
:param timeout: 超时时间
|
||||
:param args:
|
||||
@@ -159,7 +151,7 @@ class KeyWordDriver:
|
||||
def page_load_timeout(self, timeout: float, *args, **kwargs) -> None:
|
||||
self.driver.set_page_load_timeout(timeout)
|
||||
|
||||
def get(self, url, *args, **kwargs):
|
||||
def get(self, url:str, *args, **kwargs):
|
||||
if self.driver is None:
|
||||
self.browser(*args, **kwargs)
|
||||
if not url.startswith("http"):
|
||||
@@ -326,7 +318,8 @@ class KeyWordDriver:
|
||||
|
||||
if __name__ == '__main__':
|
||||
from commons.settings import configs
|
||||
el = KeyWordDriver()
|
||||
|
||||
el = CoreDriver()
|
||||
el.base_url(configs.base_url)
|
||||
# el.browser("chrome")
|
||||
el.browser(Browser.EDGE)
|
||||
@@ -338,4 +331,3 @@ if __name__ == '__main__':
|
||||
type_value = el.get_attribute("", '//*[@id="root"]/div[1]/div/div/form/div[3]/button', "type")
|
||||
print(type_value)
|
||||
el.assert_text_equals("", '//*[@id="root"]/div[1]/div/div/form/div[3]/button', "登录")
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ class Browser(str, Enum):
|
||||
IE = "ie"
|
||||
SAFARI = "safari"
|
||||
EDGE = "edge"
|
||||
DEFAULT = "default"
|
||||
|
||||
|
||||
class Locator(str, Enum):
|
||||
|
||||
@@ -43,6 +43,11 @@ EXCHANGER = Path(ROOT_PATH, "extract.toml")
|
||||
# 自增ID
|
||||
ID_PATH = Path(ROOT_PATH, "id.toml")
|
||||
|
||||
browser_dir: Path | str | None = None
|
||||
|
||||
chrome_driver: Path | str | None = None
|
||||
temp_user_data_dir: Path | str
|
||||
|
||||
# 默认配置
|
||||
DEFAULT_CONF = {
|
||||
"SCREENSHOT_DIR": SCREENSHOT_DIR,
|
||||
@@ -103,7 +108,6 @@ class Settings:
|
||||
|
||||
new_conf = DEFAULT_CONF | result
|
||||
for key, value in new_conf.items():
|
||||
|
||||
self.__setattr__(key, value)
|
||||
return self
|
||||
|
||||
@@ -134,4 +138,3 @@ configs = Settings()
|
||||
if __name__ == '__main__':
|
||||
...
|
||||
print(configs.items())
|
||||
|
||||
|
||||
@@ -9,17 +9,12 @@
|
||||
@date: 2025/4/2 21:57
|
||||
@desc:
|
||||
"""
|
||||
import json
|
||||
import logging
|
||||
from itertools import chain
|
||||
import inspect
|
||||
|
||||
import allure
|
||||
from pytest_xlsx.file import XlsxItem
|
||||
import pytest
|
||||
from selenium.webdriver import Chrome
|
||||
|
||||
from POM.login_page import LoginPage
|
||||
from POM.page.login_page import LoginPage
|
||||
from commons.driver import KeyWordDriver
|
||||
from utils.file_processors.file_handle import FileHandle
|
||||
from commons.templates import Template
|
||||
|
||||
26
excel_handle.py
Normal file
26
excel_handle.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
"""
|
||||
@author: CNWei
|
||||
@Software: PyCharm
|
||||
@contact: t6i888@163.com
|
||||
@file: excel_handle
|
||||
@date: 2025/3/30 15:09
|
||||
@desc:
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class ExcelHandler:
|
||||
def __init__(self, path: Path) -> None:
|
||||
self.path = path
|
||||
|
||||
|
||||
def load(self):
|
||||
pass
|
||||
|
||||
|
||||
def save(self):
|
||||
pass
|
||||
|
||||
@@ -4,8 +4,7 @@ version = "0.1.0"
|
||||
description = "Web自动化测试框架"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
]
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
|
||||
30
settings.toml
Normal file
30
settings.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
# settings.toml - 示例配置文件
|
||||
# 如果此文件存在,这里的配置将覆盖代码中的默认值
|
||||
|
||||
base_url = "http://production.example.com:8080" # 覆盖默认的 base_url
|
||||
screenshot = "data/screenshots" # 相对于项目根目录的路径
|
||||
|
||||
[database]
|
||||
host = "192.168.1.100" # 覆盖数据库主机
|
||||
port = 3307 # 覆盖数据库端口
|
||||
user = "prod_user"
|
||||
password = "prod_password_secret"
|
||||
database = "production_db"
|
||||
|
||||
[allure]
|
||||
epic = "项目 V2:核心功能"
|
||||
feature = "用户管理模块"
|
||||
|
||||
[rsa]
|
||||
public = """-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyourPublicKeyHere...
|
||||
-----END PUBLIC KEY-----"""
|
||||
private = """-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-128-CBC,yourEncryptedPrivateKeyInfoHere...
|
||||
|
||||
-----END RSA PRIVATE KEY-----"""
|
||||
|
||||
# 注意:cases_dir, exchanger, id_path, test_dir 也可以在这里覆盖
|
||||
# cases_dir = "MyTestCases/Answer" # 如果是相对路径,是相对于 root_path
|
||||
# test_dir = "/absolute/path/to/tests" # 也可以是绝对路径
|
||||
Binary file not shown.
139
utils/finder.py
Normal file
139
utils/finder.py
Normal file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
"""
|
||||
@author: CNWei
|
||||
@Software: PyCharm
|
||||
@contact: t6i888@163.com
|
||||
@file: finder
|
||||
@date: 2026/1/25 16:56
|
||||
@desc:
|
||||
"""
|
||||
from typing import Literal, Final
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
ByType = Literal[
|
||||
# By(selenium)
|
||||
"id", "xpath", "link text", "partial link text", "name", "tag name", "class name", "css selector",
|
||||
# 自定义常用简写 (Shortcuts)
|
||||
"lt","plt", "class", "css",
|
||||
]
|
||||
|
||||
|
||||
class FinderConverter:
|
||||
"""
|
||||
定位查找转换工具类
|
||||
提供策略的归一化处理、简写映射及动态自定义注册
|
||||
"""
|
||||
|
||||
# 预设的常用简写
|
||||
_BUILTIN_SHORTCUTS: Final = {
|
||||
"lt": By.LINK_TEXT,
|
||||
"plt": By.PARTIAL_LINK_TEXT,
|
||||
"class": By.CLASS_NAME,
|
||||
"css": By.CSS_SELECTOR,
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self._finder_map: dict[str, str] = {}
|
||||
self._map_cache: dict[str, str] = {}
|
||||
self._initialize()
|
||||
|
||||
@staticmethod
|
||||
def _normalize(text: str) -> str:
|
||||
"""
|
||||
统一清洗逻辑:转小写、去除空格、下划线、横杠
|
||||
"""
|
||||
if not isinstance(text, str):
|
||||
raise TypeError(f"Locator strategy must be a string, got {type(text).__name__} instead.")
|
||||
return text.lower().strip().replace('_', '').replace(' ', '').replace('-', '')
|
||||
|
||||
def _initialize(self) -> None:
|
||||
"""初始化基础映射表"""
|
||||
# 1. 动态加载 AppiumBy 常量值
|
||||
for attr_name in dir(By):
|
||||
if attr_name.startswith("_"):
|
||||
continue
|
||||
|
||||
attr_value = getattr(By, attr_name)
|
||||
if isinstance(attr_value, str):
|
||||
# "class name" -> classname,"class_name" -> classname
|
||||
self._finder_map[self._normalize(attr_value)] = attr_value
|
||||
|
||||
# 2. 加载内置简写(会覆盖同名的策略)
|
||||
self._finder_map.update(self._BUILTIN_SHORTCUTS)
|
||||
|
||||
# 3. 备份初始状态
|
||||
self._map_cache = self._finder_map.copy()
|
||||
|
||||
def convert(self, by_value: ByType | str) -> str:
|
||||
"""
|
||||
将模糊或简写的定位方式转换为 Appium 标准定位字符串
|
||||
:raises ValueError: 当定位方式不支持时抛出
|
||||
"""
|
||||
if not by_value or not isinstance(by_value, str):
|
||||
raise ValueError(f"Invalid selector type: {type(by_value)}. Expected a string.")
|
||||
|
||||
clean_key = self._normalize(by_value)
|
||||
target = self._finder_map.get(clean_key)
|
||||
|
||||
if target is None:
|
||||
raise ValueError(f"Unsupported locator strategy: '{by_value}'.")
|
||||
return target
|
||||
|
||||
def register_custom_finder(self, alias: str, target: str) -> None:
|
||||
"""注册自定义定位策略"""
|
||||
self._finder_map[self._normalize(alias)] = target
|
||||
|
||||
def clear_custom_finders(self) -> None:
|
||||
"""重置回初始官方/内置状态"""
|
||||
self._finder_map = self._map_cache.copy()
|
||||
|
||||
def get_all_finders(self) -> list[str]:
|
||||
"""返回当前所有支持的策略 key(用于调试)"""
|
||||
return list(self._finder_map.keys())
|
||||
|
||||
|
||||
# 导出单例,方便直接使用
|
||||
converter = FinderConverter()
|
||||
by_converter = converter.convert
|
||||
register_custom_finder = converter.register_custom_finder
|
||||
|
||||
__all__ = ["by_converter", "register_custom_finder"]
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 1. 测试标准转换与内置简写
|
||||
print(f"ID 转换: {by_converter('id')}") # 输出: id
|
||||
print(f"Class 简写转换: {by_converter('class')}") # 输出: accessibility id
|
||||
print(f"CSS 简写转换: {by_converter('css')}") # 输出: css selector
|
||||
|
||||
# 2. 测试强大的归一化容错 (空格、下划线、横杠、大小写)
|
||||
print(f"类链容错: {by_converter(' link_text ')}") # 输出: link text
|
||||
print(f"PARTIAL_LINK_TEXT 容错: {by_converter('PARTIAL_LINK_TEXT')}") # 输出: partial link text
|
||||
|
||||
# 3. 测试自定义注册
|
||||
register_custom_finder("my_text", "-my uiautomator")
|
||||
print(f"自定义注册测试: {by_converter('my_text')}") # 输出: -my uiautomator
|
||||
|
||||
# 4. 测试重置功能
|
||||
converter.clear_custom_finders()
|
||||
print("已重置自定义查找器")
|
||||
try:
|
||||
by_converter("my_text")
|
||||
except ValueError as e:
|
||||
print(f"验证重置成功 (捕获异常): {e}")
|
||||
|
||||
# 5. 查看当前全量支持的归一化后的 Key
|
||||
print(f"当前支持的策略总数: {len(converter.get_all_finders())}")
|
||||
print(f"前 5 个策略示例: {converter.get_all_finders()[:5]}")
|
||||
# 6. 增加类型非法测试
|
||||
print("\n--- 异常类型测试 ---")
|
||||
try:
|
||||
by_converter(123) # 传入数字
|
||||
except TypeError as e:
|
||||
print(f"验证类型拦截成功: {e}")
|
||||
|
||||
try:
|
||||
by_converter(None) # 传入 None
|
||||
except TypeError as e:
|
||||
print(f"验证空值拦截成功: {e}")
|
||||
Reference in New Issue
Block a user