【测试】Web页面UI自动化测试完全指南:8步通用测试框架

目录

  • Web页面UI自动化测试完全指南:8步通用测试框架
    • 一、框架概述
      • [1.1 什么是8步通用测试框架?](#1.1 什么是8步通用测试框架?)
      • [1.2 为什么是这8步?](#1.2 为什么是这8步?)
    • 二、环境准备
      • [2.1 项目结构(以仅测试登录页面为例)](#2.1 项目结构(以仅测试登录页面为例))
      • [2.2 依赖安装](#2.2 依赖安装)
      • [2.3 配置文件](#2.3 配置文件)
    • 三、基础代码
      • [3.1 基础页面类](#3.1 基础页面类)
      • [3.2 登录页面类](#3.2 登录页面类)
    • 四、8步测试详解与代码
      • [4.1 第1步:元素存在性测试](#4.1 第1步:元素存在性测试)
      • [4.2 第2步:正常路径测试](#4.2 第2步:正常路径测试)
      • [4.3 第3步:异常路径测试](#4.3 第3步:异常路径测试)
      • [4.4 第4步:边界值测试](#4.4 第4步:边界值测试)
      • [4.5 第5步:页面跳转测试](#4.5 第5步:页面跳转测试)
      • [4.6 第6步:交互体验测试](#4.6 第6步:交互体验测试)
      • [4.7 第7步:UI样式测试](#4.7 第7步:UI样式测试)
      • [4.8 第8步:兼容性测试](#4.8 第8步:兼容性测试)
    • 五、Pytest配置
    • 六、运行测试
      • [6.1 运行命令](#6.1 运行命令)
      • [6.2 测试结果](#6.2 测试结果)
    • 七、总结
      • [7.1 8步框架快速记忆](#7.1 8步框架快速记忆)
      • [7.2 框架适用性](#7.2 框架适用性)
      • [7.3 核心原则](#7.3 核心原则)

Web页面UI自动化测试完全指南:8步通用测试框架

一套适用于任何Web页面的测试方法论,包含测试要点、代码示例和最佳实践


一、框架概述

1.1 什么是8步通用测试框架?

这是一个系统化的Web页面测试方法论,无论你测试的是登录页、购物车、商品详情还是个人中心,都可以按照这8个步骤来设计测试用例。

步骤 测试类型 核心问题
第1步 元素存在性 页面上的东西都在吗?
第2步 正常路径 正确操作能成功吗?
第3步 异常路径 错误操作有提示吗?
第4步 边界值 极端输入能处理吗?
第5步 页面跳转 链接点得对、跳得对吗?
第6步 交互体验 键盘、鼠标操作顺滑吗?
第7步 UI样式 颜色、字体、布局对吗?
第8步 兼容性 不同浏览器/分辨率正常吗?

1.2 为什么是这8步?

复制代码
用户使用页面的完整路径:
1. 看到页面(元素存在)
2. 输入信息(正常操作)
3. 可能输错(异常处理)
4. 极端情况(边界值)
5. 点击链接(页面跳转)
6. 键盘鼠标(交互体验)
7. 视觉感受(UI样式)
8. 不同设备(兼容性)

这8步覆盖了用户使用页面的所有场景!

二、环境准备

2.1 项目结构(以仅测试登录页面为例)

复制代码
shopping_ui_test/
├── config/
│   ├── config.yaml           # 环境配置
│   └── test_data.yaml        # 测试数据
├── pages/
│   ├── base_page.py          # 基础页面类
│   └── login_page.py         # 登录页面类
├── testcases/
│   └── test_login.py         # 测试用例
├── utils/
│   ├── driver_factory.py     # 浏览器驱动管理
│   ├── data_loader.py        # 数据加载
│   └── logger.py             # 日志
├── conftest.py               # pytest配置
├── pytest.ini                # pytest配置
├── requirements.txt          # 依赖
├── screenshots/              # 截图目录
└── reports/                  # 报告目录

2.2 依赖安装

bash 复制代码
pip install pytest selenium webdriver-manager pyyaml allure-pytest

2.3 配置文件

config/config.yaml

yaml 复制代码
environment: "test"
url:
  base_url: "https://example.com"
  login: "/login.html"
browser:
  name: "chrome"
  headless: false
timeout:
  implicit_wait: 10
  explicit_wait: 15

config/test_data.yaml

yaml 复制代码
valid_user:
  username: "admin"
  password: "123456"

invalid_users:
  - username: "admin"
    password: "wrong"
    expected: "密码错误"
  - username: "nonexist"
    password: "123456"
    expected: "账号不存在"

三、基础代码

3.1 基础页面类

python 复制代码
# pages/base_page.py
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
import os
from datetime import datetime


class BasePage:
    """所有页面类的基类,封装公共方法"""
    
    def __init__(self, driver):
        self.driver = driver
        self.wait = WebDriverWait(driver, 10)
    
    # ========== 元素定位 ==========
    def find_element(self, locator, timeout=10):
        """等待并查找单个元素"""
        wait = WebDriverWait(self.driver, timeout)
        return wait.until(EC.presence_of_element_located(locator))
    
    def find_elements(self, locator, timeout=10):
        """等待并查找多个元素"""
        wait = WebDriverWait(self.driver, timeout)
        return wait.until(EC.presence_of_all_elements_located(locator))
    
    def is_element_present(self, locator, timeout=2):
        """判断元素是否存在"""
        try:
            self.find_element(locator, timeout)
            return True
        except TimeoutException:
            return False
    
    def is_element_visible(self, locator, timeout=5):
        """判断元素是否可见"""
        try:
            wait = WebDriverWait(self.driver, timeout)
            wait.until(EC.visibility_of_element_located(locator))
            return True
        except TimeoutException:
            return False
    
    # ========== 元素操作 ==========
    def click(self, locator, timeout=10):
        """点击元素"""
        wait = WebDriverWait(self.driver, timeout)
        element = wait.until(EC.element_to_be_clickable(locator))
        element.click()
    
    def input_text(self, locator, text, timeout=10, clear_first=True):
        """输入文本"""
        element = self.find_element(locator, timeout)
        if clear_first:
            element.clear()
        element.send_keys(text)
    
    def get_text(self, locator, timeout=10):
        """获取元素文本"""
        return self.find_element(locator, timeout).text
    
    def get_attribute(self, locator, attribute, timeout=10):
        """获取元素属性"""
        return self.find_element(locator, timeout).get_attribute(attribute)
    
    # ========== 页面信息 ==========
    def get_current_url(self):
        """获取当前URL"""
        return self.driver.current_url
    
    def get_page_title(self):
        """获取页面标题"""
        return self.driver.title
    
    def refresh(self):
        """刷新页面"""
        self.driver.refresh()
    
    # ========== 等待 ==========
    def wait_for_url_contains(self, text, timeout=10):
        """等待URL包含指定文本"""
        wait = WebDriverWait(self.driver, timeout)
        wait.until(EC.url_contains(text))
    
    def wait_for_url_to_be(self, url, timeout=10):
        """等待URL完全匹配"""
        wait = WebDriverWait(self.driver, timeout)
        wait.until(EC.url_to_be(url))
    
    # ========== 截图 ==========
    def take_screenshot(self, name=None):
        """截图并保存"""
        screenshot_dir = "screenshots"
        if not os.path.exists(screenshot_dir):
            os.makedirs(screenshot_dir)
        
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"{name}_{timestamp}.png" if name else f"{timestamp}.png"
        filepath = os.path.join(screenshot_dir, filename)
        self.driver.save_screenshot(filepath)
        print(f"截图已保存: {filepath}")
        return filepath
    
    # ========== CSS属性获取 ==========
    def get_css_color(self, locator, property_name):
        """获取元素的CSS颜色值"""
        element = self.find_element(locator)
        return element.value_of_css_property(property_name)
    
    def get_element_size(self, locator):
        """获取元素尺寸"""
        element = self.find_element(locator)
        return element.size
    
    def get_element_location(self, locator):
        """获取元素位置"""
        element = self.find_element(locator)
        return element.location

3.2 登录页面类

python 复制代码
# pages/login_page.py
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from .base_page import BasePage


class LoginPage(BasePage):
    """登录页面对象"""
    
    # ========== 元素定位器 ==========
    USERNAME_INPUT = (By.ID, "username")
    PASSWORD_INPUT = (By.ID, "password")
    LOGIN_BUTTON = (By.ID, "loginBtn")
    REGISTER_LINK = (By.LINK_TEXT, "注册")
    FORGOT_PASSWORD_LINK = (By.LINK_TEXT, "找回密码")
    ERROR_MSG = (By.CLASS_NAME, "error")
    REMEMBER_CHECKBOX = (By.ID, "remember")
    
    # ========== 页面操作方法 ==========
    def login(self, username, password):
        """执行登录操作"""
        self.input_text(self.USERNAME_INPUT, username)
        self.input_text(self.PASSWORD_INPUT, password)
        self.click(self.LOGIN_BUTTON)
    
    def login_with_enter(self, username, password):
        """使用Enter键登录"""
        self.input_text(self.USERNAME_INPUT, username)
        password_input = self.find_element(self.PASSWORD_INPUT)
        password_input.send_keys(password)
        password_input.send_keys(Keys.ENTER)
    
    def get_error_message(self):
        """获取错误提示"""
        return self.get_text(self.ERROR_MSG)
    
    def is_login_success(self):
        """判断是否登录成功"""
        return "index" in self.get_current_url() or "home" in self.get_current_url()
    
    def click_register_link(self):
        """点击注册链接"""
        self.click(self.REGISTER_LINK)
    
    def click_forgot_password_link(self):
        """点击找回密码链接"""
        self.click(self.FORGOT_PASSWORD_LINK)
    
    def check_remember_me(self):
        """勾选记住密码"""
        self.click(self.REMEMBER_CHECKBOX)
    
    # ========== 元素存在性判断 ==========
    def has_username_input(self):
        return self.is_element_present(self.USERNAME_INPUT)
    
    def has_password_input(self):
        return self.is_element_present(self.PASSWORD_INPUT)
    
    def has_login_button(self):
        return self.is_element_present(self.LOGIN_BUTTON)
    
    # ========== 交互操作 ==========
    def tab_to_password(self):
        """从用户名框按Tab键到密码框"""
        username_input = self.find_element(self.USERNAME_INPUT)
        username_input.send_keys(Keys.TAB)
    
    def is_password_focused(self):
        """判断密码框是否获得焦点"""
        return self.driver.switch_to.active_element == self.find_element(self.PASSWORD_INPUT)
    
    # ========== UI样式验证 ==========
    def get_login_button_color(self):
        """获取登录按钮背景色"""
        return self.get_css_color(self.LOGIN_BUTTON, "background-color")
    
    def is_password_masked(self):
        """判断密码框是否为掩码模式"""
        password_input = self.find_element(self.PASSWORD_INPUT)
        return password_input.get_attribute("type") == "password"
    
    def get_username_input_width(self):
        """获取用户名框宽度"""
        return self.get_element_size(self.USERNAME_INPUT)['width']
    
    def get_password_input_width(self):
        """获取密码框宽度"""
        return self.get_element_size(self.PASSWORD_INPUT)['width']
    
    def get_input_spacing(self):
        """获取两个输入框之间的间距"""
        username_input = self.find_element(self.USERNAME_INPUT)
        password_input = self.find_element(self.PASSWORD_INPUT)
        
        username_bottom = username_input.location['y'] + username_input.size['height']
        password_top = password_input.location['y']
        
        return password_top - username_bottom

四、8步测试详解与代码

4.1 第1步:元素存在性测试

测什么: 页面上用户必须用到的元素是否存在

python 复制代码
# testcases/test_login.py
import pytest
from pages.login_page import LoginPage


class TestLogin:
    
    @pytest.fixture(autouse=True)
    def open_page(self, driver, base_url):
        driver.get(base_url + "/login.html")
        self.login_page = LoginPage(driver)
    
    # ========== 第1步:元素存在性测试 ==========
    def test_username_input_exists(self):
        """用户名输入框存在"""
        assert self.login_page.has_username_input(), "用户名输入框不存在"
    
    def test_password_input_exists(self):
        """密码输入框存在"""
        assert self.login_page.has_password_input(), "密码输入框不存在"
    
    def test_login_button_exists(self):
        """登录按钮存在"""
        assert self.login_page.has_login_button(), "登录按钮不存在"
    
    def test_register_link_exists(self):
        """注册链接存在"""
        assert self.login_page.is_element_present(self.login_page.REGISTER_LINK), "注册链接不存在"
    
    def test_forgot_password_link_exists(self):
        """找回密码链接存在"""
        assert self.login_page.is_element_present(self.login_page.FORGOT_PASSWORD_LINK), "找回密码链接不存在"

4.2 第2步:正常路径测试

测什么: 正确操作是否能成功完成功能

python 复制代码
    # ========== 第2步:正常路径测试 ==========
    def test_login_success(self, valid_user):
        """正确用户名+正确密码 → 登录成功"""
        self.login_page.login(valid_user["username"], valid_user["password"])
        
        # 验证跳转到首页
        self.login_page.wait_for_url_contains("index")
        assert self.login_page.is_login_success(), "登录成功但未跳转到首页"

4.3 第3步:异常路径测试

测什么: 错误操作是否有正确的提示信息

python 复制代码
    # ========== 第3步:异常路径测试 ==========
    @pytest.mark.parametrize("username,password,expected", [
        ("admin", "wrong", "密码错误"),
        ("nonexist", "123456", "账号不存在"),
    ])
    def test_login_fail(self, username, password, expected):
        """错误信息 → 显示正确提示"""
        self.login_page.login(username, password)
        
        error_msg = self.login_page.get_error_message()
        assert expected in error_msg, f'期望包含"{expected}",实际: "{error_msg}"'

4.4 第4步:边界值测试

测什么: 极端输入(空值、超长、特殊字符)能否正确处理

python 复制代码
    # ========== 第4步:边界值测试 ==========
    @pytest.mark.parametrize("username,password,expected", [
        ("", "123456", "请输入用户名"),
        ("admin", "", "请输入密码"),
        ("", "", "请输入用户名"),
        ("a" * 100, "123456", "用户名不能超过"),
        ("<script>alert(1)</script>", "123456", "用户名格式不正确"),
    ])
    def test_boundary_values(self, username, password, expected):
        """边界值测试:空值、超长、特殊字符"""
        self.login_page.login(username, password)
        
        error_msg = self.login_page.get_error_message()
        assert expected in error_msg, f'期望包含"{expected}",实际: "{error_msg}"'

4.5 第5步:页面跳转测试

测什么: 链接点击后能否正确跳转

python 复制代码
    # ========== 第5步:页面跳转测试 ==========
    def test_register_link_jump(self):
        """点击注册链接 → 跳转到注册页"""
        original_url = self.login_page.get_current_url()
        
        self.login_page.click_register_link()
        
        # 验证URL变了
        assert self.login_page.get_current_url() != original_url
        assert "register" in self.login_page.get_current_url()
        
        # 验证页面内容正确
        assert "用户注册" in self.login_page.get_page_title()
    
    def test_forgot_password_link_jump(self):
        """点击找回密码链接 → 跳转到找回密码页"""
        self.login_page.click_forgot_password_link()
        
        assert "forgot" in self.login_page.get_current_url() or "reset" in self.login_page.get_current_url()
        assert "找回密码" in self.login_page.get_page_title()
    
    def test_back_button_after_jump(self):
        """跳转后浏览器后退 → 返回原页面"""
        original_url = self.login_page.get_current_url()
        
        self.login_page.click_register_link()
        assert self.login_page.get_current_url() != original_url
        
        self.login_page.driver.back()
        assert self.login_page.get_current_url() == original_url

4.6 第6步:交互体验测试

测什么: 键盘操作、按钮状态、悬停效果等交互体验

python 复制代码
    # ========== 第6步:交互体验测试 ==========
    def test_tab_key_navigation(self):
        """Tab键切换焦点"""
        # 初始焦点在用户名框
        username_input = self.login_page.find_element(self.login_page.USERNAME_INPUT)
        assert self.login_page.driver.switch_to.active_element == username_input
        
        # Tab到密码框
        self.login_page.tab_to_password()
        assert self.login_page.is_password_focused()
    
    def test_enter_key_submit(self, valid_user):
        """Enter键提交登录"""
        self.login_page.login_with_enter(valid_user["username"], valid_user["password"])
        self.login_page.wait_for_url_contains("index")
        assert self.login_page.is_login_success()
    
    def test_button_disable_after_click(self):
        """点击后按钮变灰,防止重复提交"""
        login_btn = self.login_page.find_element(self.login_page.LOGIN_BUTTON)
        
        assert login_btn.is_enabled()
        
        self.login_page.login("admin", "123456")
        
        # 注意:实际项目中,点击后立即变灰,这里可能需要快速验证
        # 或者测试"同意协议"按钮的置灰/启用状态
        # assert not login_btn.is_enabled()

4.7 第7步:UI样式测试

测什么: 颜色、字体、间距、对齐是否符合设计稿

python 复制代码
    # ========== 第7步:UI样式测试 ==========
    def test_login_button_color(self):
        """登录按钮颜色正确"""
        color = self.login_page.get_login_button_color()
        # 设计稿要求:#1890ff → RGB(24, 144, 255)
        assert color == "rgb(24, 144, 255)" or color == "#1890ff", \
            f"按钮颜色错误,期望: rgb(24,144,255),实际: {color}"
    
    def test_password_masked(self):
        """密码框是掩码显示"""
        assert self.login_page.is_password_masked(), "密码框应该显示为***"
    
    def test_error_message_color(self):
        """错误提示文字是红色"""
        self.login_page.login("admin", "wrong")
        color = self.login_page.get_css_color(self.login_page.ERROR_MSG, "color")
        assert color == "rgb(255, 0, 0)" or color == "#ff0000", \
            f"错误提示颜色错误,应该是红色,实际: {color}"
    
    def test_input_width_consistent(self):
        """输入框宽度一致"""
        username_width = self.login_page.get_username_input_width()
        password_width = self.login_page.get_password_input_width()
        assert username_width == password_width, \
            f"输入框宽度不一致:用户名框{username_width}px,密码框{password_width}px"
    
    def test_input_spacing(self):
        """输入框间距正确"""
        spacing = self.login_page.get_input_spacing()
        # 设计稿要求:20px
        assert spacing == 20, f"输入框间距错误,期望20px,实际{spacing}px"
    
    def test_button_width(self):
        """按钮宽度正确"""
        button_size = self.login_page.get_element_size(self.login_page.LOGIN_BUTTON)
        assert button_size['width'] == 320, f"按钮宽度错误,期望320px,实际{button_size['width']}px"
        assert button_size['height'] == 40, f"按钮高度错误,期望40px,实际{button_size['height']}px"

4.8 第8步:兼容性测试

测什么: 不同浏览器、不同分辨率下页面是否正常

python 复制代码
    # ========== 第8步:兼容性测试 ==========
    @pytest.mark.parametrize("width,height,device", [
        (1920, 1080, "桌面大屏"),
        (1366, 768, "桌面小屏"),
        (375, 667, "手机竖屏"),
        (768, 1024, "平板竖屏"),
    ])
    def test_responsive_layout(self, driver, base_url, width, height, device):
        """响应式布局测试"""
        driver.set_window_size(width, height)
        driver.get(base_url + "/login.html")
        
        login_page = LoginPage(driver)
        
        # 验证核心元素存在
        assert login_page.has_username_input()
        assert login_page.has_login_button()
        
        # 验证没有横向滚动条(移动端除外)
        if width >= 768:
            scroll_width = driver.execute_script("return document.body.scrollWidth")
            window_width = driver.execute_script("return window.innerWidth")
            assert scroll_width <= window_width, f"{device}出现横向滚动条"
        
        # 截图保存
        login_page.take_screenshot(f"login_{device}_{width}x{height}")
    
    def test_cross_browser_visual(self, driver, base_url):
        """多浏览器视觉效果(需要在conftest中配置多浏览器)"""
        driver.get(base_url + "/login.html")
        
        browser_name = driver.capabilities['browserName']
        version = driver.capabilities.get('browserVersion', 'unknown')
        
        login_page = LoginPage(driver)
        
        # 验证核心功能
        assert login_page.has_username_input()
        
        # 截图保存,用于人工对比
        login_page.take_screenshot(f"login_{browser_name}_{version}")

五、Pytest配置

5.1 conftest.py

python 复制代码
# conftest.py
import pytest
import os
from datetime import datetime
from utils.driver_factory import DriverFactory
from utils.data_loader import DataLoader
from utils.logger import log


def pytest_addoption(parser):
    """添加命令行参数"""
    parser.addoption("--browser", default="chrome", choices=["chrome", "firefox", "edge"])
    parser.addoption("--headless", action="store_true", default=False)


@pytest.fixture(scope="session")
def driver(request):
    """浏览器驱动 fixture"""
    browser = request.config.getoption("--browser")
    headless = request.config.getoption("--headless")
    
    driver = DriverFactory.get_driver(browser=browser, headless=headless)
    yield driver
    driver.quit()


@pytest.fixture(scope="session")
def base_url():
    """基础URL fixture"""
    config = DataLoader.get_config()
    return config["url"]["base_url"]


@pytest.fixture
def valid_user():
    """有效用户 fixture"""
    data = DataLoader.get_test_data()
    return data["valid_user"]


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    """测试失败时自动截图"""
    outcome = yield
    report = outcome.get_result()
    
    if report.when == "call" and report.failed:
        driver = item.funcargs.get("driver")
        if driver:
            screenshot_dir = "screenshots"
            os.makedirs(screenshot_dir, exist_ok=True)
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"{item.name}_{timestamp}.png"
            filepath = os.path.join(screenshot_dir, filename)
            driver.save_screenshot(filepath)
            log.error(f"测试失败,截图已保存: {filepath}")

5.2 pytest.ini

ini 复制代码
# pytest.ini
[pytest]

# 测试发现规则
python_files = test_*.py
python_classes = Test*
python_functions = test_*

# 命令行参数
addopts = 
    -v
    -s
    --strict-markers
    --tb=short

# 自定义标记
markers =
    p0: 核心功能测试
    p1: 重要功能测试
    p2: 次要功能测试
    ui: UI样式测试
    compatibility: 兼容性测试

# 测试目录
testpaths = testcases

# 日志配置
log_cli = true
log_cli_level = INFO
log_cli_format = %(asctime)s - %(levelname)s - %(message)s
log_cli_date_format = %H:%M:%S

六、运行测试

6.1 运行命令

bash 复制代码
# 运行所有测试
pytest testcases/test_login.py -v -s

# 运行特定步骤(通过标记)
pytest testcases/test_login.py -m "not ui" -v -s

# 运行单个测试
pytest testcases/test_login.py::TestLogin::test_login_success -v -s

# 指定浏览器
pytest testcases/test_login.py --browser=firefox -v -s

# 无头模式运行
pytest testcases/test_login.py --headless -v -s

# 生成HTML报告
pytest testcases/test_login.py --html=reports/report.html --self-contained-html

6.2 测试结果

复制代码
============================= test session starts =============================
collected 20 items

testcases/test_login.py::TestLogin::test_username_input_exists PASSED
testcases/test_login.py::TestLogin::test_password_input_exists PASSED
testcases/test_login.py::TestLogin::test_login_button_exists PASSED
testcases/test_login.py::TestLogin::test_login_success PASSED
testcases/test_login.py::TestLogin::test_login_fail[admin-wrong-密码错误] PASSED
testcases/test_login.py::TestLogin::test_boundary_values[--123456-请输入用户名] PASSED
...

============================= 20 passed in 45.23s =============================

七、总结

7.1 8步框架快速记忆

步骤 一句话 代码关键点
1 东西都在吗? is_element_present()
2 正确能成功吗? login() + assert
3 错误有提示吗? get_error_message()
4 极端能处理吗? @parametrize 边界值
5 链接跳得对吗? click + assert URL
6 键盘鼠标顺滑吗? send_keys(Keys.TAB)
7 颜色布局对吗? value_of_css_property()
8 不同设备正常吗? set_window_size()

7.2 框架适用性

复制代码
✅ 登录页     ✅ 注册页     ✅ 搜索页
✅ 商品列表   ✅ 商品详情   ✅ 购物车
✅ 订单页     ✅ 个人中心   ✅ 后台管理

任何有用户交互的Web页面都适用!

7.3 核心原则

  1. 先测基础,再测复杂(元素存在 → 功能 → 样式)
  2. 先测正常,再测异常(成功路径 → 失败路径)
  3. 自动化截图(失败时自动保留证据)
  4. 数据驱动(测试数据与代码分离)

这个框架可以让你拿到任何一个新页面时,都能系统化地设计测试用例,不会遗漏重要的测试点。

相关推荐
星栈独行5 小时前
Makepad、egui、Dioxus、Tauri:Rust GUI 到底怎么选
开发语言·后端·程序人生·ui·rust
skywalk81636 小时前
nginx的配置软件Nginx UI
运维·nginx·ui
め.7 小时前
UIFramework
ui·unity
互联网散修7 小时前
鸿蒙实战:图片编辑器——添加文字的UI适配与键盘避让
ui·编辑器·harmonyos
YJlio8 小时前
OpenClaw v2026.5.26-beta.1 / beta.2 预发布解读:Gateway 加速、transcript 路径统一、多通道修复、语音增强与安装更新链路加固
人工智能·windows·python·ui·缓存·gateway·outlook
Roc-xb1 天前
hermes-web-ui安装教程
前端·ui·hermes-web-ui
xiami_world1 天前
从prompt到产品:AI 生成 UI 的三条技术路径对比与工程实践
人工智能·ui·ai·prompt·aigc·ai编程
ZC跨境爬虫1 天前
跟着 MDN 学CSS day_50:(传统布局方法与网格系统)
前端·css·ui·tensorflow·媒体
文创工作室1 天前
Adobe Photoshop 2024 多国语言版本
ui·adobe·photoshop