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 使用稳定的定位器

  • 优先使用 IDname 等唯一属性。
  • 避免使用可能变化的文本或索引。
# 推荐
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

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务