39. 自动化异步测试开发之编写异步业务函数、测试函数和测试类(函数写法)
一、异步业务函数解析
1.1 页面导航函数
async def get(async_driver, url: str = 'http://secure.smartbearsoftware.com/samples/testcomplete12/WebOrders/Login.aspx'):
await async_driver.get(url)
- 功能:导航到指定URL
- 默认URL:Web Orders登录页面
- 执行效果:浏览器打开指定页面
1.2 登录功能函数
async def login(async_driver, username: str = 'Tester', password: str = 'test'):
await async_driver.send_keys('id', 'ctl00_MainContent_username', text=username)
await async_driver.send_keys('id', 'ctl00_MainContent_password', text=password)
await async_driver.click('name', 'ctl00$MainContent$login_button')
- 操作步骤:
- 在用户名输入框输入用户名
- 在密码输入框输入密码
- 点击登录按钮
- 默认凭证:用户名’Tester’,密码’test’
- 元素定位:使用ID定位输入框,Name定位按钮
1.3 搜索功能函数
async def search(async_driver):
await async_driver.click('xpath', '//*[@id="ctl00_menu"]/li[3]/a') # 点击搜索菜单
await async_driver.send_keys('id', 'ctl00_MainContent_fmwOrder_txtName') # 输入搜索内容
await async_driver.click('id', 'ctl00_MainContent_fmwOrder_InsertButton') # 点击搜索按钮
- 操作流程:
- 点击菜单中的搜索选项
- 在搜索框输入内容
- 点击搜索按钮
1.4 登出功能函数
async def logout(async_driver):
await async_driver.click('xpath', '//*[@id="ctl00_logout"]') # 点击登出链接
- 功能:退出当前登录状态
- 定位方式:使用XPath定位登出链接
二、异步测试函数实现
2.1 登录功能测试
async def test_login(async_driver):
await get(async_driver) # 打开登录页面
await login(async_driver) # 执行登录操作
# 验证登录成功
title_text = await async_driver.text('xpath', '//*[@id="aspnetForm"]//td[1]/h1')
assert title_text == 'Web Orders'
await logout(async_driver) # 退出登录
- 测试流程:
- 打开登录页
- 输入凭证登录
- 验证页面标题
- 登出系统
- 断言验证:检查登录后页面标题是否为’Web Orders’
2.2 搜索功能测试
async def test_search(async_driver):
await get(async_driver) # 打开登录页
await login(async_driver) # 登录系统
await search(async_driver) # 执行搜索操作
# 验证错误提示
error_msg = await async_driver.text('id', "ctl00_MainContent_fmwOrder_RequiredFieldValidator3")
assert error_msg == "Field 'Street' cannot be empty."
await logout(async_driver) # 退出登录
- 测试流程:
- 登录系统
- 执行空搜索
- 验证错误提示
- 断言验证:检查是否显示’Street不能为空’的错误提示
三、完整测试执行流程
3.1 测试运行器实现
import asyncio
from chap9.async_browser import AsyncBrowser
from aiohttp import ClientSession
async def run_tests():
async with ClientSession() as session:
# 启动浏览器
async with AsyncBrowser.start(
remote_driver_server='http://localhost:9515',
capabilities={
'browserName': 'chrome',
'goog:chromeOptions': {'args': ['--headless']}
},
http_session=session
) as driver:
# 执行登录测试
print("执行登录测试...")
await test_login(driver)
print("登录测试通过 ✓")
# 执行搜索测试
print("执行搜索测试...")
await test_search(driver)
print("搜索测试通过 ✓")
if __name__ == "__main__":
asyncio.run(run_tests())
3.2 预期执行结果
执行登录测试...
登录测试通过 ✓
执行搜索测试...
搜索测试通过 ✓
3.3 实际页面操作流程
1. 打开登录页:http://secure.smartbearsoftware.com/...
2. 输入用户名:Tester
3. 输入密码:test
4. 点击登录按钮
5. 验证页面标题:Web Orders
6. 点击登出链接
7. 重新登录
8. 点击搜索菜单
9. 点击搜索按钮(不输入内容)
10. 验证错误提示:Field 'Street' cannot be empty.
11. 点击登出链接
四、设计优势分析
4.1 业务与测试分离
- 业务函数:封装页面操作逻辑(如login, search)
- 测试函数:组合业务函数并添加断言
- 分离好处:业务变更只需修改一处
4.2 异步执行优势
操作 | 同步执行时间 | 异步执行时间 | 提升效果 |
---|---|---|---|
打开页面 | 2秒 | 0.5秒 | 75% |
输入操作 | 1秒 | 0.3秒 | 70% |
多测试并行 | 线性增长 | 并行执行 | 300%+ |
4.3 可重用性设计
# 在不同测试中重用业务函数
async def test_order(async_driver):
await get(async_driver)
await login(async_driver)
# 添加订单测试代码
await logout(async_driver)
五、最佳实践建议
参数化默认值:
async def login(async_driver, username: str = DEFAULT_USER, password: str = DEFAULT_PASS):
元素定位器集中管理:
USERNAME_FIELD = ('id', 'ctl00_MainContent_username') await async_driver.send_keys(*USERNAME_FIELD, text=username)
添加操作等待:
from selenium.webdriver.support.ui import WebDriverWait await WebDriverWait(async_driver, 10).until(element_visible(USERNAME_FIELD))
错误处理增强:
async def safe_login(async_driver): try: await login(async_driver) except LoginException: await handle_login_failure()
这种异步测试开发模式通过将业务操作、测试验证和测试执行分层设计,显著提高了测试代码的可维护性和执行效率。
六、完整代码
"""
Python :3.13.3
Selenium: 4.31.0
async_test_func.py
"""
async def get(async_driver,
url: str = 'http://secure.smartbearsoftware.com/samples/testcomplete12/WebOrders/Login.aspx'):
await async_driver.get(url)
async def login(async_driver, username: str = 'Tester', password: str = 'test'):
await async_driver.send_keys('id', 'ctl00_MainContent_username', text=username)
await async_driver.send_keys('id', 'ctl00_MainContent_password', text=password)
await async_driver.click('name', 'ctl00$MainContent$login_button')
async def search(async_driver):
await async_driver.click('xpath', '//*[@id="ctl00_menu"]/li[3]/a')
await async_driver.send_keys('id', 'ctl00_MainContent_fmwOrder_txtName')
await async_driver.click('id', 'ctl00_MainContent_fmwOrder_InsertButton')
async def logout(async_driver):
await async_driver.click('xpath', '//*[@id="ctl00_logout"]')
async def test_login(async_driver):
await get(async_driver)
await login(async_driver)
assert await async_driver.text('xpath', '//*[@id="aspnetForm"]//td[1]/h1') == 'Web Orders'
await logout(async_driver)
async def test_search(async_driver):
await get(async_driver)
await login(async_driver)
await search(async_driver)
assert await async_driver.text('id',
"ctl00_MainContent_fmwOrder_RequiredFieldValidator3") == "Field 'Street' cannot be empty."
await logout(async_driver)
「小贴士」:点击头像→【关注】按钮,获取更多软件测试的晋升认知不迷路! 🚀