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 ClientSessionasync 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.0async_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)
「小貼士」:點擊頭像→【關注】按鈕,獲取更多軟件測試的晉升認知不迷路! 🚀