第4篇:企业级框架搭建,Pytest+PO模式从0到1实战

前言:Hello 大家好!我是励志死磕计算机 ~ 前面3篇我们已经掌握了UI自动化的基础技能:环境搭建、元素定位、核心操作。但相信大家在练习中已经发现了问题------写的脚本都是零散的,改一个元素定位要在多个脚本里改,无法批量执行,也没有测试报告。这就是新手和企业级自动化的核心差距:是否有规范的框架支撑。今天这篇文章,我们就从"写脚本"升级到"做项目",手把手教大家用Pytest测试框架+PO模式,搭建一个可复用、易维护、可扩展的企业级UI自动化基础框架,全程代码实战,复制就能用!

本文核心目标:

  • 理解企业级自动化框架的核心价值,搞懂"为什么需要框架"

  • 熟练掌握Pytest测试框架核心用法(Fixture、参数化、测试报告)

  • 理解并落地PO模式(Page Object Model)分层设计思想

  • 从0到1搭建完整框架,包含页面对象层、测试用例层、工具层、配置层

  • 掌握框架运行与问题排查技巧,适配企业真实测试场景

一、先搞懂:为什么需要企业级框架?

在开始搭建之前,我们先明确"框架"的核心作用。新手写的自动化脚本,通常会遇到以下4个痛点,而框架就是为了解决这些问题而生的!

1. 新手零散脚本的4大痛点

  • 代码冗余:多个脚本重复写驱动初始化、元素定位、操作步骤,改一处要改多处

  • 维护困难:页面元素变更后,需要在所有用到该元素的脚本中修改,成本极高

  • 无法批量执行:只能单个脚本运行,无法一次性执行所有用例,效率低下

  • 无测试报告:运行结果需要手动查看控制台,无法生成直观的报告供团队查看

2. 企业级框架的核心要求

一个合格的企业级UI自动化框架,必须满足"可复用、易维护、可扩展、可监控"4个核心要求:

  • 可复用:常用操作(如驱动初始化、登录、截图)封装成公共方法,多个用例直接调用

  • 易维护:页面元素和操作集中管理,元素变更只需修改一处,不影响用例

  • 可扩展:支持新增页面、新增用例时快速集成,无需重构整个框架

  • 可监控:能批量执行用例,生成详细测试报告,支持失败重试、自动截图,方便问题定位

3. 为什么选Pytest+PO模式?

这是目前企业中最主流的UI自动化框架组合,优势互补:

  • Pytest:Python生态中最强大的测试框架,支持Fixture前置后置、参数化、测试报告、失败重试等企业级特性,比Python自带的unittest更灵活、易用

  • PO模式:页面对象模型(Page Object Model),核心是"页面元素与操作封装、测试用例与页面分离",从设计层面解决代码冗余和维护困难的问题

二、前置准备:环境依赖安装

搭建框架前,先安装所需的依赖库,打开cmd/终端执行以下命令(建议创建虚拟环境,避免依赖冲突):

复制代码
# 安装Pytest(测试框架核心)
pip install pytest==7.4.0  # 指定稳定版本,避免兼容性问题

# 安装Pytest-HTML(生成基础测试报告)
pip install pytest-html==3.2.0

# 安装Selenium(UI自动化核心)
pip install selenium==4.11.2

# 安装webdriver-manager(自动管理浏览器驱动)
pip install webdriver-manager==4.0.0

# 安装python-dotenv(读取配置文件)
pip install python-dotenv==1.0.0

验证安装成功:执行pytest --version,若输出Pytest版本信息(如pytest 7.4.0),则说明安装成功。

三、Pytest测试框架核心用法(企业级必备)

Pytest是框架的"骨架",负责用例管理、执行、报告生成等核心功能。我们先掌握最关键的4个特性,这是搭建框架的基础。

1. 测试用例规范(必须遵守)

Pytest有严格的用例命名规范,不遵守则无法识别用例:

  • 测试文件:以test_开头(如test_login.py)或_test结尾(如login_test.py)

  • 测试类:以Test开头,且不能有__init__方法(如TestLogin)

  • 测试方法/函数:以test_开头(如test_login_success)

  • 断言:使用Python原生的assert语句(如assert "登录成功" in driver.page_source)

示例(符合规范的用例):

复制代码
# 文件名:test_login.py
class TestLogin:
    def test_login_success(self):
        # 测试登录成功场景
        assert "登录成功" in "当前页面显示:登录成功"
    
    def test_login_fail(self):
        # 测试登录失败场景
        assert "用户名错误" in "当前页面显示:用户名错误"

2. Fixture:前置/后置操作的"万能工具"

Fixture是Pytest的核心特性,用于封装前置操作(如驱动初始化、打开浏览器)和后置操作(如关闭浏览器、清理数据),替代传统的setup/teardown,支持全局复用、作用域控制。

(1)基础用法:定义与调用

创建conftest.py文件(Pytest会自动识别该文件中的Fixture,无需导入):

复制代码
# 文件名:conftest.py
import pytest
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

# 定义Fixture,作用域为function(默认),每个测试函数执行前都会调用
@pytest.fixture(scope="function")
def init_driver():
    # 前置操作:初始化驱动、打开浏览器
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.maximize_window()  # 最大化窗口
    driver.implicitly_wait(10)  # 隐式等待10秒
    yield driver  # yield之前是前置操作,之后是后置操作
    
    # 后置操作:关闭浏览器
    driver.quit()

在测试用例中调用Fixture(直接作为参数传入):

复制代码
# 文件名:test_login.py
class TestLogin:
    # 直接将Fixture名作为参数传入,Pytest会自动执行前置操作
    def test_login_success(self, init_driver):
        driver = init_driver
        # 访问登录页
        driver.get("https://xxx.com/login")
        # 输入账号密码
        driver.find_element_by_id("username").send_keys("test_user")
        driver.find_element_by_id("password").send_keys("test_pass")
        driver.find_element_by_id("login_btn").click()
        # 断言登录成功
        assert "欢迎您,test_user" in driver.page_source
(2)Fixture作用域(关键)

通过scope参数控制Fixture的作用范围,企业级框架常用3种:

  • scope="function":默认值,每个测试函数执行前都调用(最常用,保证用例隔离)

  • scope="class":每个测试类执行前调用一次

  • scope="module":每个测试文件执行前调用一次

示例(类级作用域):

复制代码
@pytest.fixture(scope="class")
def init_class_driver():
    # 前置操作:初始化驱动
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.maximize_window()
    driver.implicitly_wait(10)
    yield driver
    # 后置操作:关闭驱动
    driver.quit()

3. 参数化:多组数据批量执行用例

企业测试中经常需要用多组数据验证同一功能(如不同账号登录、不同参数输入),Pytest的@pytest.mark.parametrize装饰器可实现参数化,批量执行用例。

示例(多账号登录测试):

复制代码
# 文件名:test_login.py
import pytest

class TestLogin:
    # 参数化装饰器:第一个参数是参数名(可多个),第二个参数是测试数据(列表/元组)
    @pytest.mark.parametrize("username, password, expected_result", [
        ("test_user1", "test_pass1", "欢迎您,test_user1"),  # 正常登录
        ("test_user2", "wrong_pass", "用户名或密码错误"),     # 密码错误
        ("wrong_user", "test_pass3", "用户名或密码错误"),     # 用户名错误
        ("", "", "请输入用户名")                              # 空值校验
    ])
    def test_login_parametrize(self, init_driver, username, password, expected_result):
        driver = init_driver
        driver.get("https://xxx.com/login")
        # 输入参数化的账号密码
        driver.find_element_by_id("username").send_keys(username)
        driver.find_element_by_id("password").send_keys(password)
        driver.find_element_by_id("login_btn").click()
        # 断言预期结果
        assert expected_result in driver.page_source

运行后会自动生成4条测试用例,分别执行4组数据,效率大幅提升!

4. 测试报告:pytest-html生成直观报告

企业级测试需要直观的报告展示用例执行结果,pytest-html可生成HTML格式的测试报告,支持显示用例详情、失败原因、截图等。

(1)生成基础报告

在cmd/终端中进入项目目录,执行以下命令:

复制代码
# -v:详细输出用例执行信息
# -s:打印用例中的print日志
# --html=report.html:生成名为report.html的测试报告,存放在当前目录
pytest -v -s --html=report.html test_login.py

执行完成后,项目目录会生成report.html文件,用浏览器打开即可查看报告,包含用例通过率、执行时间、失败详情等信息。

(2)报告优化:添加截图(失败自动截图)

在conftest.py中添加失败截图逻辑,用例失败时自动保存截图并嵌入报告:

复制代码
# 文件名:conftest.py
import pytest
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from datetime import datetime
import os

# 定义截图保存路径
SCREENSHOT_DIR = "./screenshots"
if not os.path.exists(SCREENSHOT_DIR):
    os.makedirs(SCREENSHOT_DIR)

@pytest.fixture(scope="function")
def init_driver(request):  # 添加request参数,用于获取用例信息
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.maximize_window()
    driver.implicitly_wait(10)
    
    # 定义后置操作:失败截图
    def fin():
        # 判断用例是否失败
        if request.node.rep_call.failed:
            # 生成截图文件名(用例名+时间戳)
            timestamp = datetime.strftime(datetime.now(), "%Y%m%d%H%M%S")
            screenshot_name = f"{request.node.name}_{timestamp}.png"
            screenshot_path = os.path.join(SCREENSHOT_DIR, screenshot_name)
            # 保存截图
            driver.save_screenshot(screenshot_path)
            print(f"用例失败,截图已保存至:{screenshot_path}")
    
    # 注册后置操作
    request.addfinalizer(fin)
    yield driver
    driver.quit()

# 用于捕获用例执行结果(必须添加,否则无法判断用例是否失败)
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    rep = outcome.get_result()
    # 存储用例执行结果到item对象中
    setattr(item, "rep_call", rep)

再次运行生成报告的命令,失败用例会自动保存截图,打开报告后可直接查看截图,方便问题定位。

四、PO模式:企业级框架的"灵魂"设计

PO模式(Page Object Model)是一种设计模式,核心思想是"将每个页面封装成一个对象,页面的元素和操作都集中在该对象中,测试用例只调用页面对象的方法,不直接操作元素"。这样可以实现"页面与用例分离",大幅降低维护成本。

1. PO模式三大核心原则

  • 页面元素与操作封装:每个页面的元素(如id、XPath)和操作(如输入账号、点击登录)都封装在对应的页面对象类中

  • 测试用例与页面分离:测试用例不关心页面的具体元素和操作细节,只调用页面对象的方法完成流程

  • 复用性优先:公共页面(如导航栏、 Footer)可封装成公共页面对象,供其他页面复用

2. PO模式四层架构(企业标准)

搭建框架时,我们采用四层架构设计,目录结构清晰,职责明确:

复制代码
ui_auto_framework/  # 项目根目录
├── config/          # 配置层:存储全局配置(URL、账号、等待时间等)
│   └── config.py    # 配置文件
├── pages/           # 页面对象层:封装各页面的元素和操作
│   ├── base_page.py # 基础页面(封装公共操作,如等待、截图)
│   ├── login_page.py# 登录页面对象
│   └── home_page.py # 首页面对象
├── tests/           # 测试用例层:编写测试用例
│   └── test_login.py# 登录相关测试用例
├── utils/           # 工具层:封装公共工具(日志、截图、读取配置等)
│   └── logger.py    # 日志工具
├── conftest.py      # Pytest Fixture配置文件
└── requirements.txt # 项目依赖库清单

3. 各层实现实战(核心步骤)

下面我们逐一实现各层代码,以"登录页→首页"的流程为例。

(1)配置层:config/config.py

存储全局配置信息,避免硬编码(如URL、账号密码),方便后续修改:

复制代码
# 文件名:config/config.py
# 全局配置信息
class Config:
    # 基础URL
    BASE_URL = "https://xxx.com"
    # 登录页URL
    LOGIN_URL = f"{BASE_URL}/login"
    # 首页URL
    HOME_URL = f"{BASE_URL}/home"
    # 测试账号密码
    TEST_USERNAME = "test_user"
    TEST_PASSWORD = "test_pass"
    # 等待时间(秒)
    IMPLICITLY_WAIT = 10
    EXPLICITLY_WAIT = 15

# 实例化配置对象,供其他模块调用
config = Config()
(2)工具层:utils/logger.py(日志工具)

封装日志工具,用于记录测试过程(如用例开始、操作步骤、失败异常),方便问题定位:

复制代码
# 文件名:utils/logger.py
import logging
import os
from datetime import datetime

# 日志保存路径
LOG_DIR = "./logs"
if not os.path.exists(LOG_DIR):
    os.makedirs(LOG_DIR)

# 日志文件名(时间戳)
LOG_FILE = f"{LOG_DIR}/test_log_{datetime.strftime(datetime.now(), '%Y%m%d')}.log"

# 配置日志格式
logging.basicConfig(
    level=logging.INFO,  # 日志级别:INFO及以上会被记录
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",  # 日志格式
    handlers=[
        logging.FileHandler(LOG_FILE, encoding="utf-8"),  # 写入文件
        logging.StreamHandler()  # 输出到控制台
    ]
)

# 创建日志对象,供其他模块调用
logger = logging.getLogger("UI_AUTO_LOG")
(3)页面对象层:base_page.py(基础页面)

封装所有页面的公共操作(如显式等待、点击、输入、截图),其他页面对象继承该类:

复制代码
# 文件名:pages/base_page.py
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from utils.logger import logger
from config.config import config

class BasePage:
    def __init__(self, driver):
        self.driver = driver
        self.base_url = config.BASE_URL
        self.explicitly_wait = config.EXPLICITLY_WAIT

    # 访问页面
    def open(self, url):
        logger.info(f"访问页面:{url}")
        self.driver.get(url)

    # 显式等待元素可点击
    def wait_element_clickable(self, locator):
        try:
            element = WebDriverWait(self.driver, self.explicitly_wait).until(
                EC.element_to_be_clickable(locator)
            )
            logger.info(f"元素可点击:{locator}")
            return element
        except TimeoutException:
            logger.error(f"等待元素可点击超时:{locator}")
            raise

    # 显式等待元素可见
    def wait_element_visible(self, locator):
        try:
            element = WebDriverWait(self.driver, self.explicitly_wait).until(
                EC.visibility_of_element_located(locator)
            )
            logger.info(f"元素可见:{locator}")
            return element
        except TimeoutException:
            logger.error(f"等待元素可见超时:{locator}")
            raise

    # 点击操作
    def click(self, locator):
        element = self.wait_element_clickable(locator)
        element.click()
        logger.info(f"点击元素:{locator}")

    # 输入操作
    def input_text(self, locator, text):
        element = self.wait_element_visible(locator)
        element.clear()
        element.send_keys(text)
        logger.info(f"向元素{locator}输入文本:{text}")

    # 获取元素文本
    def get_element_text(self, locator):
        element = self.wait_element_visible(locator)
        text = element.text
        logger.info(f"获取元素{locator}文本:{text}")
        return text

    # 截图操作
    def screenshot(self, filename):
        screenshot_path = f"./screenshots/{filename}.png"
        self.driver.save_screenshot(screenshot_path)
        logger.info(f"截图保存至:{screenshot_path}")
        return screenshot_path
(4)页面对象层:login_page.py(登录页面)

继承BasePage,封装登录页的专属元素和操作(如输入账号、输入密码、点击登录):

复制代码
# 文件名:pages/login_page.py
from pages.base_page import BasePage
from selenium.webdriver.common.by import By
from config.config import config

class LoginPage(BasePage):
    # 页面元素定位器(元组格式:(定位方式, 定位值))
    USERNAME_INPUT = (By.ID, "username")  # 账号输入框
    PASSWORD_INPUT = (By.ID, "password")  # 密码输入框
    LOGIN_BUTTON = (By.ID, "login_btn")   # 登录按钮
    ERROR_MESSAGE = (By.CLASS_NAME, "error_msg")  # 错误提示信息
    WELCOME_MESSAGE = (By.ID, "welcome_msg")  # 登录成功欢迎信息

    # 登录操作(核心方法)
    def login(self, username, password):
        self.open(config.LOGIN_URL)  # 访问登录页
        self.input_text(self.USERNAME_INPUT, username)  # 输入账号
        self.input_text(self.PASSWORD_INPUT, password)  # 输入密码
        self.click(self.LOGIN_BUTTON)  # 点击登录

    # 获取错误提示信息
    def get_error_message(self):
        return self.get_element_text(self.ERROR_MESSAGE)

    # 获取登录成功欢迎信息
    def get_welcome_message(self):
        return self.get_element_text(self.WELCOME_MESSAGE)
(5)页面对象层:home_page.py(首页)

封装首页的元素和操作,用于验证登录后跳转是否正确:

复制代码
# 文件名:pages/home_page.py
from pages.base_page import BasePage
from selenium.webdriver.common.by import By
from config.config import config

class HomePage(BasePage):
    # 页面元素定位器
    USER_INFO = (By.ID, "user_info")  # 用户信息展示区
    LOGOUT_BUTTON = (By.ID, "logout_btn")  # 退出登录按钮

    # 验证是否进入首页
    def is_home_page(self):
        return config.HOME_URL in self.driver.current_url

    # 获取当前登录用户名
    def get_current_username(self):
        return self.get_element_text(self.USER_INFO)

    # 退出登录
    def logout(self):
        self.click(self.LOGOUT_BUTTON)
        logger.info("执行退出登录操作")
(6)测试用例层:tests/test_login.py

调用页面对象的方法编写测试用例,不涉及任何元素定位细节:

复制代码
# 文件名:tests/test_login.py
import pytest
from pages.login_page import LoginPage
from pages.home_page import HomePage
from config.config import config
from utils.logger import logger

class TestLogin:
    # 测试登录成功场景
    def test_login_success(self, init_driver):
        logger.info("开始执行测试用例:test_login_success")
        driver = init_driver
        # 初始化页面对象
        login_page = LoginPage(driver)
        home_page = HomePage(driver)
        
        # 执行登录操作(调用登录页对象的方法)
        login_page.login(config.TEST_USERNAME, config.TEST_PASSWORD)
        
        # 断言:是否跳转到首页
        assert home_page.is_home_page(), "登录后未跳转到首页"
        # 断言:首页显示当前用户名
        assert config.TEST_USERNAME in home_page.get_current_username(), "首页未显示正确的用户名"
        logger.info("测试用例:test_login_success 执行成功")

    # 测试登录失败场景(参数化)
    @pytest.mark.parametrize("username, password, expected_error", [
        ("test_user", "wrong_pass", "用户名或密码错误"),
        ("wrong_user", "test_pass", "用户名或密码错误"),
        ("", "", "请输入用户名")
    ])
    def test_login_fail(self, init_driver, username, password, expected_error):
        logger.info(f"开始执行测试用例:test_login_fail,参数:{username}, {password}")
        driver = init_driver
        login_page = LoginPage(driver)
        
        # 执行登录操作
        login_page.login(username, password)
        
        # 断言:显示正确的错误提示
        assert login_page.get_error_message() == expected_error, f"错误提示不正确,预期:{expected_error}"
        logger.info(f"测试用例:test_login_fail({username})执行成功")
(7)Fixture配置:conftest.py

整合驱动初始化、日志、截图等功能,供用例调用:

复制代码
# 文件名:conftest.py
import pytest
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from config.config import config
from utils.logger import logger
import os
from datetime import datetime

# 截图保存路径
SCREENSHOT_DIR = "./screenshots"
if not os.path.exists(SCREENSHOT_DIR):
    os.makedirs(SCREENSHOT_DIR)

# 驱动初始化Fixture
@pytest.fixture(scope="function")
def init_driver(request):
    logger.info("开始初始化浏览器驱动")
    # 初始化Chrome驱动
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.maximize_window()
    driver.implicitly_wait(config.IMPLICITLY_WAIT)
    logger.info("浏览器驱动初始化完成")

    # 后置操作:失败截图+关闭驱动
    def fin():
        logger.info("开始执行后置操作")
        # 用例失败截图
        if request.node.rep_call.failed:
            timestamp = datetime.strftime(datetime.now(), "%Y%m%d%H%M%S")
            screenshot_name = f"{request.node.name}_{timestamp}"
            driver.save_screenshot(f"{SCREENSHOT_DIR}/{screenshot_name}.png")
            logger.error(f"用例执行失败,截图已保存:{screenshot_name}.png")
        # 关闭驱动
        driver.quit()
        logger.info("浏览器驱动已关闭")

    request.addfinalizer(fin)
    yield driver

# 捕获用例执行结果
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    rep = outcome.get_result()
    setattr(item, "rep_call", rep)

# 自定义命令行参数(可选,用于指定环境)
def pytest_addoption(parser):
    parser.addoption("--env", action="store", default="test", help="指定测试环境:test/prod")

@pytest.fixture(scope="session")
def env(request):
    return request.config.getoption("--env")
(8)依赖清单:requirements.txt

记录项目所有依赖库及版本,方便他人快速搭建环境:

复制代码
pytest==7.4.0
pytest-html==3.2.0
selenium==4.11.2
webdriver-manager==4.0.0
python-dotenv==1.0.0

五、框架运行与问题排查

框架搭建完成后,我们学习如何运行用例、查看报告,以及常见问题的排查方法。

1. 框架运行命令

进入项目根目录,执行以下命令(根据需求选择):

复制代码
# 1. 运行指定测试文件
pytest tests/test_login.py -v -s

# 2. 运行所有测试用例(tests目录下所有符合规范的用例)
pytest -v -s

# 3. 运行指定标记的用例(需先给用例加标记,如@pytest.mark.smoke)
pytest -v -s -m smoke

# 4. 生成测试报告并指定报告路径
pytest -v -s --html=reports/test_report.html tests/test_login.py

# 5. 失败重试(需安装pytest-rerunfailures:pip install pytest-rerunfailures)
pytest -v -s --reruns=2 tests/test_login.py  # 失败后重试2次

2. 常见问题排查

(1)Fixture作用域冲突

问题:用例中调用的Fixture作用域不匹配(如类级Fixture被函数级用例调用)。

解决方案:统一Fixture作用域,优先使用function级作用域保证用例隔离;若需使用类级/模块级,确保所有调用的用例都适配。

(2)页面对象元素定位错误

问题:运行用例时提示"no such element",但元素定位表达式正确。

解决方案:检查是否需要显式等待(BasePage中已封装,确保调用了wait_element_clickable/wait_element_visible方法);检查元素是否在iframe中(需在BasePage中添加iframe切换方法)。

(3)测试报告无法生成

问题:执行生成报告命令后,未生成report.html文件。

解决方案:检查pytest-html是否安装成功(pip show pytest-html);确保命令中的报告路径正确(如reports目录需提前创建)。

(4)用例失败未截图

问题:用例失败后未生成截图。

解决方案:检查conftest.py中是否添加了pytest_runtest_makereport钩子函数(用于捕获用例执行结果);检查screenshots目录是否存在(代码中已添加自动创建逻辑)。

六、实战练习(巩固框架)

请基于上面搭建的框架,完成以下实战练习,巩固PO模式和Pytest的使用:

需求:新增"商品搜索"功能的测试用例,涵盖以下场景:

  1. 新增商品页面对象(product_page.py),封装商品搜索框、搜索按钮、搜索结果列表等元素和操作。

  2. 在tests目录下新增test_product.py,编写测试用例:

    1. 搜索存在的商品(如"Python编程书籍"),断言搜索结果正确。

    2. 搜索不存在的商品(如"xxx123456"),断言显示"无相关商品"提示。

    3. 搜索空值,断言显示"请输入搜索关键词"提示。

  3. 运行用例并生成测试报告,验证框架的复用性和可扩展性。

提示:新增页面对象时,继承BasePage类,复用公共操作;编写用例时,调用页面对象的方法,不直接操作元素。

七、总结与下一篇预告

本篇文章我们完成了企业级UI自动化框架的从0到1搭建,核心知识点总结:

  • 框架的核心价值:解决零散脚本的冗余、维护难问题,实现可复用、易维护、可监控。

  • Pytest核心特性:Fixture(前置后置)、参数化(多组数据)、测试报告(直观展示)。

  • PO模式四层架构:配置层、工具层、页面对象层、测试用例层,职责清晰,分离解耦。

  • 框架搭建关键:公共操作封装、元素定位集中管理、用例与页面分离。

下一篇文章我们将对框架进行进阶优化,学习数据驱动(Excel/JSON)、日志体系强化、失败重试等企业级特性,解决"多数据测试、问题定位难、脚本不稳定"三大核心痛点,让框架更贴合企业真实测试需求!

如果这篇文章对你有帮助,别忘了点赞+收藏+关注,后续会持续更新UI自动化系列教程~ 有任何问题欢迎在评论区留言!

专栏地址:【保姆级实战】UI自动化从入门到企业落地全系列(持续更新)

相关推荐
软件聚导航16 小时前
马年、我用AI写了个“打工了马” 小程序
人工智能·ui·微信小程序
摘星编程17 小时前
OpenHarmony + RN:Calendar日期选择功能
python
Yvonne爱编码17 小时前
JAVA数据结构 DAY3-List接口
java·开发语言·windows·python
一方_self17 小时前
了解和使用python的click命令行cli工具
开发语言·python
小芳矶17 小时前
Dify本地docker部署踩坑记录
python·docker·容器
2301_8223663518 小时前
使用Scikit-learn构建你的第一个机器学习模型
jvm·数据库·python
小郎君。18 小时前
【无标题】
python
喵手19 小时前
Python爬虫实战:数据治理实战 - 基于规则与模糊匹配的店铺/公司名实体消歧(附CSV导出 + SQLite持久化存储)!
爬虫·python·数据治理·爬虫实战·零基础python爬虫教学·规则与模糊匹配·店铺公司名实体消岐
喵手19 小时前
Python爬虫实战:国际电影节入围名单采集与智能分析系统:从数据抓取到获奖预测(附 CSV 导出)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集数据csv导出·采集国际电影节入围名单·从数据抓取到获奖预测
柱子jason19 小时前
使用IOT-Tree Server模拟Modbus设备对接西门子PLC S7-200
网络·物联网·自动化·modbus·西门子plc·iot-tree·协议转换