1. 项目概述:为什么字符串操作是自动化测试的基石

干了这么多年自动化测试,我见过太多因为字符串处理不当而导致的“灵异事件”。一个看似简单的元素文本断言失败,背后可能藏着编码问题、空格差异或者动态内容截取错误。尤其是在像 Playwright 这样现代、高效的自动化框架里,我们与网页的交互,本质上就是一场与字符串的“博弈”。你定位元素靠的是字符串选择器,你验证结果比对的也是字符串内容,你从页面上提取的数据更是五花八门的字符串。如果字符串操作这门“内功”不扎实,你的自动化脚本就会像建立在流沙上的城堡,看似华丽,一碰就散。

《最新出炉》这个系列,咱们定位就是“入门篇”,但入门绝不意味着浅尝辄止。今天,我们就深挖一下 Python 中那些你必须掌握的字符串操作技巧,并紧密结合 Playwright 自动化测试的真实场景。你会发现,这些基础操作,才是支撑起稳定、健壮测试用例的真正骨架。无论你是刚刚接触 Playwright,想从 Selenium 转型过来,还是已经写了一些脚本但总觉得排查问题很费力,这篇关于字符串“上篇”的梳理,都能帮你把基础打牢。咱们不搞花架子,就聊实实在在的代码和踩过的坑,让你写的每一行 assert 都更有底气。

2. 核心需求解析:自动化测试中字符串操作的四大战场

在开始敲代码之前,我们得先想明白:在 Playwright 自动化测试里,我们到底在哪些地方需要和字符串“较劲”?理解了战场,才能选对武器。

2.1 战场一:元素定位与动态选择器构建

这是字符串操作最频繁的场景。Playwright 提供了多种定位方式( text= , css= , xpath= ),其中很多都需要我们动态拼接字符串。

典型场景 :你要测试一个表格,需要点击“用户姓名”为“张三”的那一行后面的“编辑”按钮。这个“张三”可能来自测试数据文件。你的选择器可能就是 'tr:has-text("张三") >> button:text("编辑")' 。这里,将变量 username = "张三" 嵌入到选择器字符串中,就是最基本的字符串格式化操作。如果用户名包含引号或特殊字符,直接拼接就会导致语法错误,脚本直接崩溃。

更深层需求 :不仅仅是简单的拼接。有时你需要从一部分文本中定位元素,比如“包含‘订单’字样的按钮”。这就需要使用字符串方法来判断或生成匹配模式。

2.2 战场二:断言验证与文本内容处理

从页面上获取到的文本( text_content() , inner_text() )很少是“干净”的。它可能包含:

  • 多余的空格和换行 :特别是从 inner_text() 获取时,会保留元素内的格式。
  • 不可见字符 :如   (不间断空格)、 \u200b (零宽空格)。
  • 动态前缀/后缀 :比如“总计:$100.00”,你只关心数字“100.00”。
  • 多语言和编码 :虽然现代网页多用 UTF-8,但偶尔也会遇到编码问题。

你的断言 assert page.text_content(‘.total’) == ‘100.00’ 很可能因为一个多余的空格而失败。因此,对获取的字符串进行“清洗”(trim, strip, replace)和“提取”(slice, split, regex)是必备技能。

2.3 战场三:测试数据准备与参数化

测试数据往往存储在外部文件(如 CSV, JSON, Excel)或从数据库读取。这些数据读入内存后,通常以字符串形式存在。你可能需要:

  • 格式化 :将字符串模板与变量结合,生成最终的测试输入(如邮件正文、地址信息)。
  • 转换 :将字符串转换为其他类型(如整数、浮点数、日期)进行业务逻辑计算,然后再转换回字符串进行输入或断言。
  • 生成 :动态生成符合特定规则的字符串,如随机邮箱、手机号、订单号,用于测试新建功能。

2.4 战场四:日志记录与报告生成

清晰易懂的日志和报告是调试和排查问题的生命线。你需要将各种变量(定位器、预期值、实际值、状态)组织成人类可读的字符串信息,记录到文件或控制台。如何格式化这些日志信息,使其在成千上万行日志中一目了然,也离不开字符串操作。

理解了这四大战场,我们就能有的放矢地学习 Python 的字符串工具箱了。接下来,我们进入实战环节,我会结合 Playwright 代码,逐一拆解这些核心操作。

3. 基础但至关重要的字符串操作三剑客

在深入复杂操作前,有三个基础方法你必须像呼吸一样自然地去使用。它们在 Playwright 脚本中出场率极高。

3.1 strip() lstrip() rstrip() :文本清洗第一步

从 Playwright 获取文本后,第一步永远是去除首尾空白字符。

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto('https://example.com')
    
    # 假设某个元素的实际HTML是:<span>  Hello World  </span>
    raw_text = page.text_content('span')  # 可能得到 "  Hello World  "
    
    # 直接断言会失败!
    # assert raw_text == "Hello World"  # False
    
    cleaned_text = raw_text.strip()
    print(f"原始文本: '{raw_text}'")   # 输出: '  Hello World  '
    print(f"清洗后文本: '{cleaned_text}'") # 输出: 'Hello World'
    
    assert cleaned_text == "Hello World"  # True
    
    browser.close()

为什么是 strip() inner_text 会保留元素内的文本格式,包括换行和缩进。 text_content 虽然好一些,但元素本身的样式或布局也可能引入空格。 strip() 能移除字符串开头和结尾的 所有 空白字符(空格、制表符 \t 、换行符 \n 、回车符 \r 等)。这是避免因格式问题导致断言失败的最简单、最有效的方法。

lstrip() rstrip() 用在哪儿? 有时你只需要去除一边的空白。例如,从输入框 get_attribute(‘value’) 获取的值,用户可能在开头误输入了空格,但结尾的空格通常会被浏览器忽略。这时用 lstrip() 更精准。或者处理某些有固定后缀的文本时,你可能只想清理开头。

实操心得 :养成条件反射,对任何从页面上 text_content() inner_text() 获取的字符串,立即调用 .strip() 。这能避免至少 30% 因格式问题导致的偶发性失败。

3.2 replace() :不仅仅是简单的替换

str.replace(old, new[, count]) 方法看似简单,但在测试数据准备和文本清理中威力巨大。

场景一:清理特定字符

# 从页面上获取的价格可能包含货币符号和千位分隔符
price_text = page.text_content(‘.price‘).strip()  # 假设得到 “$1,234.56”
# 为了转换为浮点数进行比较,需要移除 $ 和 ,
price_number = float(price_text.replace(‘$‘, ‘‘).replace(‘,‘, ‘‘))
assert price_number > 1000

场景二:处理动态内容中的固定部分

# 页面提示信息可能是:“成功创建了订单,订单号:ORD-20231027-78901”
message = page.text_content(‘.alert-success‘).strip()
# 我们只关心固定的前缀部分是否出现,可以移除动态的订单号部分进行比较
if message.replace(order_number, ‘[NUMBER]‘) == “成功创建了订单,订单号:[NUMBER]“:
    print(“订单创建成功消息正确”)

这里, order_number 是之前生成的变量。通过 replace 将动态部分替换为占位符,使得断言可以专注于静态文本。

场景三:构造包含引号的选择器(进阶) 这是一个容易踩坑的地方。如果文本内容本身包含单引号或双引号,直接拼接到选择器里会破坏语法。

username = “O‘Connor“  # 名字里有个单引号
# 错误做法:选择器字符串会提前结束
# selector = f‘button:text(“{username}“)‘  # 语法错误!
# 正确做法:使用 replace 进行转义,或者使用不同的引号
selector1 = f“button:text(‘{username}‘)“  # 用双引号包裹整个字符串,内部用单引号
# 或者,更稳妥地使用 CSS 转义或 Playwright 的转义函数(如果存在)
# 但一个简单的 replace 可以临时解决:
escaped_username = username.replace(“‘“, “\\‘“)  # 将单引号替换为转义的单引号
selector2 = f‘button:text(“{escaped_username}“)‘

注意 :对于复杂的文本,建议使用 Playwright 提供的 escape_for_selector 类的方法(如果有)或优先考虑使用其他属性(如 data-testid )进行定位,避免文本定位的脆弱性。 replace 在这里是一种应急的字符串处理手段。

3.3 split() :从大段文本中提取关键信息

当页面元素返回的是一大段文本,而你只需要其中的某一部分时, split() 是你的首选工具。它根据指定的分隔符将字符串切分成列表。

典型场景:获取表格某一行的特定列数据

# 假设一个表格行的文本内容是 “张三 30 男 zhangsan@example.com“
row_text = page.text_content(‘tr:first-child‘).strip()
columns = row_text.split()  # 默认以任何空白字符(空格、换行等)分割
print(columns)  # 输出: [‘张三‘, ‘30‘, ‘男‘, ‘zhangsan@example.com‘]
name, age, gender, email = columns  # 可以直接解包
assert name == “张三“
assert int(age) > 18  # 转换为整数进行比较

更精细的分割 : 如果数据是用特定的字符分隔的,比如逗号、制表符或“|”。

csv_line = “Apple,Red,Round,Sweet“
attributes = csv_line.split(‘,‘)
print(attributes)  # 输出: [‘Apple‘, ‘Red‘, ‘Round‘, ‘Sweet‘]

# 限制分割次数:只分割前N次
log_entry = “ERROR 2023-10-27 10:00:00 ModuleA - Something went wrong“
parts = log_entry.split(‘ ‘, 3)  # 只分割前3个空格
print(parts)  # 输出: [‘ERROR‘, ‘2023-10-27‘, ‘10:00:00‘, ‘ModuleA - Something went wrong‘]
# 这样就把日志级别、日期、时间和剩余信息分开了

在 Playwright 中的组合应用

# 获取一个包含多个子项的元素文本,如一个标签列表 “标签1, 标签2, 标签3“
tags_text = page.text_content(‘.tags‘).strip()
# 先按逗号分割,再对每个标签去除可能存在的空格
tag_list = [tag.strip() for tag in tags_text.split(‘,‘)]
print(tag_list)  # 输出: [‘标签1‘, ‘标签2‘, ‘标签3‘]
# 现在可以方便地断言标签是否存在
assert “标签2“ in tag_list

split() 方法简单粗暴有效,是快速从结构化文本中提取数据的利器。但它依赖于分隔符的稳定性,如果页面格式变化,分隔符也可能变化,导致脚本失败。因此,对于非常重要的数据提取,有时需要结合更强大的正则表达式。

4. 字符串查找与验证:确保元素“所言非虚”

自动化测试中,我们经常需要判断页面上是否存在某个文本,或者某个文本是否包含特定的关键词。这不仅仅是做断言,还常用于条件判断,决定测试流程的走向。

4.1 in 关键字与 find() :成员检查与位置定位

最直观的检查就是使用 in 关键字。

page_text = page.text_content(‘body‘).strip()
if “登录成功“ in page_text:
    print(“检测到登录成功提示,继续后续操作“)
    # ... 执行登录后的操作
else:
    print(“未发现成功提示,可能登录失败“)
    # ... 执行失败处理或断言失败

in 操作符返回布尔值,简单高效。但它只告诉你“有没有”,不告诉你“在哪里”。

如果需要知道子字符串的位置,就要用到 str.find(sub[, start[, end]]) 方法。它返回子字符串首次出现的索引(从0开始),如果没找到则返回-1。

error_message = page.text_content(‘.error-panel‘).strip()
# 查找具体的错误代码
pos = error_message.find(“ErrorCode: 500“)
if pos != -1:
    print(f“发现服务器内部错误,位置在索引 {pos}")
    # 可以基于位置进行更精细的文本截取
    # 例如,截取从错误代码开始的后50个字符
    detail = error_message[pos:pos+50]
    print(f“错误详情片段:{detail}“)
else:
    print(“未发现特定的ErrorCode 500“)

find() 在解析一些有固定格式的日志或消息时非常有用。与之类似的还有 rfind() (从右向左查找)、 index() (类似 find() ,但找不到会抛出 ValueError ,在测试脚本中通常不如 find() 安全)。

4.2 startswith() endswith() :精准的边界断言

很多时候,我们关心的是文本是否以某个特定内容开头或结尾。比如,验证成功提示、检查文件下载后的默认名称、确认URL跳转正确。

# 验证页面标题或特定提示
page_title = page.title()
if page_title.startswith(“仪表盘 - “):
    print(“成功进入仪表盘页面“)

# 验证下载的文件名
# 假设通过某些手段获取了下载的文件名(例如监听下载事件)
downloaded_file = “report_20231027.csv“
if downloaded_file.endswith(“.csv“):
    print(“文件格式正确,是CSV文件“)
    if downloaded_file.startswith(“report_“):
        print(“文件名前缀也符合规范“)

# 验证当前URL
current_url = page.url
if current_url.endswith(“/dashboard“):
    print(“当前正处于仪表盘路由下“)

这两个方法比使用 in 或正则表达式更精确、性能更好,语义也更清晰。在断言中,我强烈推荐使用它们来代替模糊的包含检查。

4.3 大小写转换与规范化比较:避免“Case-Sensitive”的坑

网页上的文本大小写可能不一致,而我们的测试数据可能是固定大小写的。直接比较会导致失败。

# 页面上显示的是 “Welcome, John!“
ui_greeting = page.text_content(‘.welcome-msg‘).strip()  # “Welcome, John!“
expected_greeting = “WELCOME, JOHN!“  # 我们的预期可能是大写的(例如来自配置)

# 直接比较失败
# assert ui_greeting == expected_greeting  # False

# 方法1:都转成小写或大写再比较
assert ui_greeting.lower() == expected_greeting.lower()  # True

# 方法2:使用 casefold() 进行更彻底的忽略大小写比较(对某些特殊字符更准确)
assert ui_greeting.casefold() == expected_greeting.casefold()

lower() vs casefold()

  • lower() :将字符串中所有大写字符转换为小写。适用于大多数英文场景。
  • casefold() :更加激进,旨在移除所有大小写区别。例如,德语字母 ‘ß‘ (sharp s)的 lower() 还是 ‘ß‘ ,但 casefold() 会变成 “ss“ 。在需要严格的无语言环境限制的大小写无关比较时(比如搜索引擎), casefold() 更合适。对于大多数 Web UI 测试, lower() upper() 已足够。

规范化操作的最佳实践 : 我建议在测试脚本中定义一个辅助函数,专门用于进行“模糊”的文本比较,将 strip() 、大小写转换、甚至替换掉不间断空格等操作封装起来。

def normalize_text(text: str) -> str:
    “”“清洗和规范化字符串,用于比较。”“”
    if not text:
        return text
    # 1. 去除首尾空白
    text = text.strip()
    # 2. 将HTML不间断空格替换为普通空格
    text = text.replace(‘\u00A0‘, ‘ ‘)
    # 3. 将多个连续空格合并为一个(可选,根据需求)
    # import re; text = re.sub(r‘\s+‘, ‘ ‘, text)
    # 4. 转换为小写
    text = text.lower()
    return text

# 使用方式
actual = normalize_text(page.text_content(‘.message‘))
expected = normalize_text(“  Your  Order  Is  Confirmed!  “) # 预期文本也可以同样处理
assert actual == expected

这个 normalize_text 函数能处理很多因格式导致的断言失败,让你的测试更加健壮。

5. 字符串格式化:动态构建选择器与日志信息

这是将静态脚本变为动态、可复用脚本的关键。Python 提供了多种字符串格式化方式,在 Playwright 脚本中,我最常用的是 f-string 和 str.format()

5.1 f-string:现代、简洁的首选

Python 3.6 引入的 f-string 是当前最推荐的方式,可读性极高。

# 1. 动态构建选择器
product_name = “Playwright Guide Book“
# 定位包含特定产品名的“加入购物车”按钮
add_to_cart_selector = f‘div.product:has-text(“{product_name}“) >> button:has-text(“Add to Cart“)‘
page.click(add_to_cart_selector)

# 2. 参数化URL
order_id = 12345
page.goto(f“https://admin.example.com/orders/{order_id}/details“)

# 3. 生成清晰的日志信息
expected_count = 10
actual_count = len(page.query_selector_all(‘.item-row‘))
# 使用 f-string 生成包含变量值的断言失败信息,调试时一目了然
assert actual_count == expected_count, f“商品数量不符,预期 {expected_count},实际 {actual_count}“

f-string 直接在字符串前加 f ,用花括号 {} 包裹变量或表达式。它支持复杂的表达式甚至函数调用(但为了可读性,不建议在内部写太复杂的逻辑)。

5.2 str.format() :更灵活的格式化控制

当需要更复杂的格式控制时,比如数字的位数、对齐方式等, format() 方法更强大。

# 控制数字格式:浮点数保留两位小数,整数补零
total_amount = 1234.5
formatted_amount = “Total: ${:.2f}“.format(total_amount)  # “Total: $1234.50“
page.fill(‘#amount‘, formatted_amount)

order_id = 42
padded_order_id = “Order #{:06d}“.format(order_id)  # “Order #000042“
assert padded_order_id in page.text_content(‘.order-header‘)

# 按位置或关键字传递参数,适合从字典等数据结构中构建字符串
log_template = “Time: {timestamp} | Level: {level} | Message: {msg}“
log_entry = log_template.format(timestamp=“2023-10-27 10:00“, level=“INFO“, msg=“Test started.“)
print(log_entry)

在 Playwright 测试中, format() 特别适合用于生成符合特定格式要求的测试数据,或者整理报告输出。

5.3 实战:封装一个安全的动态选择器构建函数

结合字符串操作和格式化,我们可以封装一个更健壮的函数来构建 Playwright 文本选择器,处理文本中的引号问题。

def build_text_selector(element_type: str = “*“, text: str = None, contains: bool = False) -> str:
    “”“
    构建一个安全的 Playwright 文本选择器。
    :param element_type: 元素类型,如 ‘button‘, ‘div‘,默认为 ‘*‘ 任何元素。
    :param text: 需要匹配的文本。
    :param contains: 如果为 True,使用 `:has-text()` 进行模糊匹配;为 False 使用 `:text-is()` 精确匹配(Playwright 1.28+)。
    :return: 构建好的选择器字符串。
    “”“
    if not text:
        return element_type
    
    # 简单转义单双引号:如果文本中有单引号,就用双引号包裹整个文本,反之亦然。
    # 这是一种简易处理,对于极端复杂的文本,可能需要更完整的转义。
    if “'“ in text and ‘“‘ in text:
        # 如果两种引号都有,优先转义单引号,并用双引号包裹
        escaped_text = text.replace(“'“, “\\‘“)
        quote_char = ‘“‘
    elif “‘“ in text:
        # 文本有单引号,用双引号包裹
        escaped_text = text
        quote_char = ‘“‘
    else:
        # 文本没有单引号,用单引号包裹(更常见)
        escaped_text = text
        quote_char = “'“
    
    if contains:
        # 使用 :has-text() 进行子串匹配
        selector = f‘{element_type}:has-text({quote_char}{escaped_text}{quote_char})‘
    else:
        # 使用 :text-is() 进行精确文本匹配(要求Playwright版本支持)
        # 或者使用老的 text= 选择器,但需要注意它也是精确匹配
        selector = f‘{element_type}:text-is({quote_char}{escaped_text}{quote_char})‘
        # 老版本兼容写法:selector = f‘{element_type}:text(“{escaped_text}“)‘  # 注意这里固定用了双引号
    
    return selector

# 使用示例
button_selector = build_text_selector(“button“, “Submit Order“)
page.click(button_selector)

# 处理包含引号的文本
weird_text_selector = build_text_selector(“span“, “O‘Connor said: \“Hello\”“)
print(weird_text_selector)  # 输出: span:has-text(“O‘Connor said: \“Hello\”“)

这个函数虽然简单,但解决了一个常见痛点。当然,对于生产级脚本,更推荐使用 data-testid 等专用测试属性来定位,完全避免文本内容的依赖。

6. 字符串拼接与性能考量:用 join() 告别低效循环

当我们需要将多个字符串片段组合成一个长的字符串时,比如生成一个长的 SQL 查询语句、构建一个复杂的 JSON 字符串体、或者拼接一个大的 HTML 片段,怎么做最高效?

错误示范(低效)

parts = [“Line 1“, “Line 2“, “Line 3“, ... “Line 1000“]
result = ““
for part in parts:
    result += part + “\n“  # 每次循环都创建一个新的字符串对象!

在 Python 中,字符串是不可变对象。每次使用 += 进行拼接,都会在内存中创建一个全新的字符串对象,并将旧对象的内容复制过去。如果循环次数很多(比如上千次),这种操作会非常消耗内存和时间。

正确做法:使用 str.join()

parts = [“Line 1“, “Line 2“, “Line 3“, ... “Line 1000“]
result = “\n“.join(parts)  # 一次性高效拼接

join() 方法接收一个可迭代对象(如列表、元组),并将其中的所有字符串元素用指定的分隔符(这里是换行符 \n )连接起来。它在内部进行了优化,性能远高于循环拼接。

在 Playwright 测试中的应用场景

# 场景1:生成一个测试用的多行地址
address_lines = [
    “John Doe“,
    “123 Main St“,
    “Suite 400“,
    “Anytown, CA 12345“
]
formatted_address = “\n“.join(address_lines)
page.fill(‘textarea#address‘, formatted_address)

# 场景2:构建一个复杂的 CSS 选择器列表(用于批量等待元素)
critical_selectors = [
    “.page-loaded-indicator“,
    “#main-content“,
    “.user-avatar“,
    “nav.main-menu“
]
# 用逗号连接,形成一个组合选择器,等待其中任何一个出现
combined_selector = “, “.join(critical_selectors)
page.wait_for_selector(combined_selector, state=“visible“)

# 场景3:生成动态的测试用例步骤描述
steps = []
steps.append(“1. 导航到登录页面“)
steps.append(f“2. 输入用户名: {test_username}“)
steps.append(f“3. 输入密码: {test_password}“)
steps.append(“4. 点击登录按钮“)
test_case_steps = “\n“.join(steps)
print(f“执行步骤:\n{test_case_steps}“)

养成使用 join() 的习惯,尤其是在循环体内构建字符串时,这是编写高效 Python 代码(包括测试脚本)的一个小但重要的技巧。

7. 字符串判断与类型安全:编写健壮的断言逻辑

自动化测试脚本必须健壮,能够优雅地处理各种边界情况,比如元素不存在(返回 None )或文本为空。直接对可能为 None 的对象调用字符串方法会导致 AttributeError

7.1 防御性编程:处理 None 和空字符串

# 不安全的写法
element = page.query_selector(‘.status-message‘)  # 可能返回 None
text = element.text_content()  # 如果 element 是 None,这里会抛出 AttributeError
if “success“ in text:  # 如果 text 是 None,这里会抛出 TypeError
    ...

# 健壮的写法
element = page.query_selector(‘.status-message‘)
if element is None:
    # 元素不存在,根据业务逻辑处理:可能是测试失败,也可能是正常状态
    print(“警告:未找到状态消息元素“)
    # 可以选择断言失败或记录日志后继续
    # pytest.fail(“状态消息元素未找到“)
else:
    text = element.text_content()
    # 进一步检查 text 是否为 None 或空(虽然 text_content() 通常返回空字符串而非None)
    if text and “success“ in text.strip().lower():
        print(“操作成功“)
    else:
        print(f“操作可能失败,状态信息为: ‘{text}‘“)

关键点

  1. 总是检查 query_selector 的返回值 。元素可能因为页面未加载、选择器错误或动态隐藏而找不到。
  2. 对字符串操作前,确认其非 None 。使用 if text: 进行判断,它等价于 if text is not None and text != ““:
  3. 结合使用 strip() 。即使有文本,也可能全是空格, if text: 会判断为 True ,但 strip() 后可能为空。

7.2 实用的断言辅助函数

为了提高代码复用性和可读性,可以封装一些常用的字符串断言函数。

def assert_text_contains(element_selector: str, expected_substring: str, page, ignore_case=True, strip=True):
    “”“断言指定元素包含某段文本。”“”
    element = page.query_selector(element_selector)
    assert element is not None, f“未找到元素: {element_selector}“
    actual_text = element.text_content()
    if actual_text is None:
        actual_text = ““
    if strip:
        actual_text = actual_text.strip()
    if ignore_case:
        actual_text = actual_text.lower()
        expected_substring = expected_substring.lower()
    
    assert expected_substring in actual_text, \
        f“元素 ‘{element_selector}‘ 的文本不包含 ‘{expected_substring}‘。实际文本: ‘{actual_text}‘“

def assert_text_equals(element_selector: str, expected_text: str, page, ignore_case=False, strip=True):
    “”“断言指定元素的文本等于预期文本。”“”
    element = page.query_selector(element_selector)
    assert element is not None, f“未找到元素: {element_selector}“
    actual_text = element.text_content()
    if actual_text is None:
        actual_text = ““
    processed_actual = actual_text.strip() if strip else actual_text
    processed_expected = expected_text.strip() if strip else expected_text
    
    if ignore_case:
        compare_result = processed_actual.lower() == processed_expected.lower()
    else:
        compare_result = processed_actual == processed_expected
    
    assert compare_result, \
        f“元素 ‘{element_selector}‘ 的文本与预期不符。\n预期: ‘{processed_expected}‘\n实际: ‘{processed_actual}‘“

# 使用示例
assert_text_contains(‘.toast-message‘, “保存成功“, page)
assert_text_equals(‘h1.page-title‘, “用户管理后台“, page, ignore_case=True)

这些函数内部处理了空值检查、文本清洗和大小写转换,让测试用例的主体部分更简洁、更专注于业务逻辑,同时也提供了清晰的断言失败信息,极大地方便了调试。

字符串操作的“上篇”我们就先探讨到这里,涵盖了从最基础的清洗、查找、格式化到性能优化和健壮性编程的核心内容。这些是构建可靠 Playwright 自动化测试脚本的基石。在下篇中,我们将深入更高级的主题,包括 正则表达式在文本提取中的威力 处理多行字符串和复杂编码 、以及如何利用字符串操作进行 数据驱动测试的封装 。掌握了这些,你就能游刃有余地应对自动化测试中 90% 以上的文本处理挑战。

更多推荐