UI 测试-保持代码稳定性
在 UI 测试中,保持代码的稳定性是确保测试可靠性和可维护性的关键。UI 测试通常依赖于外部环境(如浏览器、网络、应用程序状态等),这些因素可能导致测试结果不稳定。以下是一些保持 UI 测试代码稳定性的最佳实践和技巧:
1. 使用显式等待
显式等待是确保 UI 元素加载完成后再进行操作的关键。避免使用硬编码的 time.sleep(),因为它会导致不必要的等待或超时。
1.1 Selenium 中的显式等待
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def test_ui():
driver = webdriver.Chrome()
driver.get("https://example.com")
try:
# 等待元素加载完成
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "element-id"))
element.click()
finally:
driver.quit()
1.2 Playwright 中的显式等待
from playwright.sync_api import sync_playwright
def test_ui():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://example.com")
# 等待元素加载完成
page.wait_for_selector("#element-id")
page.click("#element-id")
browser.close()
2. 处理动态元素
UI 元素可能会因为页面加载或异步操作而动态变化。使用稳定的定位策略和等待机制来处理动态元素。
2.1 使用稳定的定位器
- 优先使用
ID、name等唯一属性。 - 避免使用可能变化的文本或索引。
# 推荐 element = driver.find_element(By.ID, "submit-button") # 不推荐 element = driver.find_element(By.XPATH, "//button[text()='Submit']")
2.2 处理动态加载内容
对于异步加载的内容,使用显式等待确保元素可用。
# 等待动态加载的内容
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "dynamic-content"))
3. 处理弹窗和异常
UI 测试中可能会遇到弹窗、网络错误或元素不可用等异常情况。需要捕获并处理这些异常。
3.1 处理弹窗
from selenium.common.exceptions import NoAlertPresentException
try:
alert = driver.switch_to.alert
alert.accept()
except NoAlertPresentException:
print("No alert found")
3.2 处理元素不可用
from selenium.common.exceptions import NoSuchElementException
try:
element = driver.find_element(By.ID, "element-id")
element.click()
except NoSuchElementException:
print("Element not found")
4. 使用 Page Object 模式
Page Object 模式是一种设计模式,将页面元素和操作封装在单独的类中,提高代码的可维护性和稳定性。
4.1 实现 Page Object
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.username_field = (By.ID, "username")
self.password_field = (By.ID, "password")
self.login_button = (By.ID, "login-button")
def enter_username(self, username):
self.driver.find_element(*self.username_field).send_keys(username)
def enter_password(self, password):
self.driver.find_element(*self.password_field).send_keys(password)
def click_login(self):
self.driver.find_element(*self.login_button).click()
def test_login():
driver = webdriver.Chrome()
driver.get("https://example.com/login")
login_page = LoginPage(driver)
login_page.enter_username("user")
login_page.enter_password("pass")
login_page.click_login()
driver.quit()
5. 减少外部依赖
UI 测试的稳定性受外部环境(如网络、第三方服务)影响。尽量减少对外部依赖的依赖。
5.1 使用 Mock 数据
对于依赖外部 API 的 UI 测试,可以使用 Mock 数据模拟 API 响应。
from unittest.mock import patch
def test_ui_with_mock():
with patch("requests.get") as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {"key": "value"}
# 执行测试
5.2 使用本地测试环境
尽量在本地或可控的环境中运行 UI 测试,避免依赖不稳定的外部服务。
6. 并行测试
并行测试可以提高测试效率,但需要确保测试之间的独立性,避免资源竞争。
6.1 使用 Selenium Grid
Selenium Grid 支持并行执行测试。
from selenium import webdriver
def test_ui():
capabilities = {
"browserName": "chrome",
"version": "latest",
"platform": "Windows 10"
}
driver = webdriver.Remote(
command_executor="http://localhost:4444/wd/hub",
desired_capabilities=capabilities
)
driver.get("https://example.com")
driver.quit()
6.2 使用 Playwright 并行测试
Playwright 支持开箱即用的并行测试。
from playwright.sync_api import sync_playwright
def test_ui():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://example.com")
browser.close()
# 使用 pytest 并行执行
# pytest -n 4
7. 日志和截图
在测试失败时,记录日志和截图可以帮助快速定位问题。
7.1 记录日志
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def test_ui():
logger.info("Starting UI test")
driver = webdriver.Chrome()
driver.get("https://example.com")
logger.info("Page loaded")
driver.quit()
7.2 截图
def test_ui():
driver = webdriver.Chrome()
driver.get("https://example.com")
try:
driver.find_element(By.ID, "element-id").click()
except Exception as e:
driver.save_screenshot("error.png")
raise e
finally:
driver.quit()
8. 定期维护测试脚本
UI 测试脚本需要定期维护,以适应应用程序的变化。
8.1 更新定位器
当 UI 发生变化时,及时更新定位器。
8.2 重构代码
定期重构测试代码,保持代码简洁和可维护性。
总结
保持 UI 测试代码的稳定性需要结合显式等待、异常处理、Page Object 模式、Mock 数据等技术。通过减少外部依赖、并行测试、记录日志和截图,以及定期维护测试脚本,可以显著提高 UI 测试的可靠性和可维护性。
《高级软件测试工程师》专栏旨在为测试领域的从业者提供深入的知识和实践指导,帮助大家从基础的测试技能迈向高级测试专家的行列。 在本专栏中,主要涵盖的内容: 1. 如何设计和实施高效的测试策略; 2. 掌握自动化测试、性能测试和安全测试的核心技术; 3. 深入理解测试驱动开发(TDD)和行为驱动开发(BDD)的实践方法; 4. 测试团队的管理和协作能力。 ——For.Heart