Python自动化测试五大框架类型解析:从单元测试到BDD的工程实践
1. 项目概述为什么Python是自动化测试的首选聊到自动化测试尤其是刚入行的朋友总会纠结于语言和框架的选择。我干了十多年测试从早期的QTP、LoadRunner到后来全面转向Python最大的感受就是选对工具效率能翻好几倍。今天咱们不聊虚的就围绕“Python自动化测试5大框架类型”这个核心掰开揉碎了讲清楚你怎么用Python把自动化测试这事儿给落地了。为什么是Python简单说就三点语法简单上手快、生态丰富轮子多、社区活跃好抄作业。你想想测试工程师的核心价值是保证质量、发现风险而不是成为编程专家。Python的语法接近自然语言一个毫无编程基础的业务测试花一两周也能看懂基本的脚本逻辑。更重要的是你想做Web UI自动化有Selenium。想做接口测试Requests库强大又简单。想做移动端Appium对Python的支持非常友好。还有像unittest、pytest这样的测试框架是内置或主流的这意味着你不需要在环境搭建和基础框架选型上耗费大量精力可以直接聚焦在业务测试逻辑本身。这五大框架类型并不是指五个具体的框架而是五种解决不同测试需求的“框架范式”或“技术栈组合”。理解了这个你才能根据自己项目的实际情况是Web应用、移动App、还是纯后端API搭出最合适、最经济的自动化测试体系。接下来我会把这五大类型逐一拆解并附上我踩过无数坑之后总结的实操方案和配置细节。2. 五大框架类型深度解析与选型指南自动化测试不是拿一个框架生搬硬套。不同的测试对象UI、接口、单元和不同的阶段开发自测、集成测试、回归测试需要的技术方案截然不同。我把它们归纳为五种类型你可以对号入座。2.1 类型一单元测试框架unittest pytest这是Python自动化测试的基石也是所有测试活动的起点。很多人觉得单元测试是开发的事其实不然。测试人员理解单元测试框架能更好地阅读开发写的单测甚至能编写一些集成度较高的“组件测试”或“服务测试”这对测试左移、提前发现缺陷至关重要。核心框架对比unittest vs pytestunittest是Python标准库自带的模仿了Java的JUnit。它的优点是“开箱即用”无需额外安装结构清晰TestCase、setUp、tearDown。但它的缺点也很明显断言方法不够丰富主要是assertEqual、assertTrue等夹具fixture机制不够灵活且需要以test_开头命名约束较多。pytest则是目前社区事实上的标准。它几乎兼容unittest的写法但更强大、更灵活。我强烈建议所有新项目都直接上pytest。为什么断言更智能直接用Python的assert语句失败时pytest能给出非常详细的差异对比比如断言两个字典不同它会直接告诉你哪个键的值不一样。夹具fixture机制强大这是pytest的灵魂。你可以用pytest.fixture装饰器定义一些准备和清理工作比如初始化数据库连接、启动浏览器然后通过函数参数的方式“注入”到测试函数中依赖管理非常优雅。插件生态丰富想生成漂亮的HTML报告有pytest-html。想控制用例执行顺序有pytest-ordering。想做分布式执行有pytest-xdist。这些插件能让你像搭积木一样扩展测试能力。实操心得如何从unittest平滑迁移到pytest如果你手头是老项目全是unittest写的别急着重写。pytest可以直接运行unittest的用例。你可以先在项目中安装pytest然后新写的用例全部用pytest风格老用例慢慢重构。一个典型的pytest用例看起来是这样的# test_user_login.py import pytest # 定义一个夹具用于准备测试数据 pytest.fixture def login_data(): return {username: test_user, password: secure_pass} # 测试函数夹具login_data作为参数自动传入 def test_login_success(login_data): # 这里是调用实际登录函数的代码 result user_login(login_data[username], login_data[password]) assert result[status] success assert session_id in result # 可以用装饰器标记用例 pytest.mark.slow def test_login_with_wrong_password(): result user_login(wrong_user, wrong_pass) assert result[status] fail assert result[code] AUTH_ERROR注意pytest默认查找当前目录下所有以test_开头或_test结尾的文件并执行其中以test_开头的函数。这是它的约定优于配置的体现能大幅减少样板代码。2.2 类型二Web UI自动化测试框架Selenium Page Object Model这是最经典、也是最容易“烂尾”的自动化类型。很多人一上来就录屏回放或者写一堆直接操作DOM元素的脚本结果页面一改脚本全废。核心痛点在于维护成本。解决方案就是采用“Selenium Page Object (PO) 设计模式”的组合。为什么是Selenium因为它支持所有主流浏览器绑定多种语言Python、Java等社区资料海量。对于Web UI自动化它几乎是唯一成熟的选择。pytest或unittest在这里扮演的是“测试执行和断言”的角色而Selenium是“浏览器操作”的工具。Page Object Model (PO模式) 的精髓PO模式不是某个框架而是一种设计思想。它的核心是将页面元素定位和页面操作行为封装成一个独立的类Page Object。测试脚本里不应该出现find_element_by_id这样的定位代码而只应该出现像login_page.input_username(admin)这样的业务语义。实操示例一个登录页面的PO封装# pages/login_page.py from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class LoginPage: # 1. 将所有元素定位器集中管理 USERNAME_INPUT (By.ID, username) PASSWORD_INPUT (By.ID, password) LOGIN_BUTTON (By.XPATH, //button[typesubmit]) ERROR_MSG (By.CLASS_NAME, alert-error) def __init__(self, driver): self.driver driver self.wait WebDriverWait(driver, 10) # 2. 封装页面操作行为 def enter_username(self, username): # 显式等待元素可交互增强脚本稳定性 element self.wait.until(EC.element_to_be_clickable(self.USERNAME_INPUT)) element.clear() element.send_keys(username) return self # 支持链式调用 def enter_password(self, password): self.wait.until(EC.element_to_be_clickable(self.PASSWORD_INPUT)).send_keys(password) return self def click_login(self): self.wait.until(EC.element_to_be_clickable(self.LOGIN_BUTTON)).click() # 3. 封装页面级断言或信息获取 def get_error_message(self): try: return self.wait.until(EC.visibility_of_element_located(self.ERROR_MSG)).text except: return None # 在测试脚本中这样使用 # test_login.py def test_failed_login(driver): # driver 可以通过pytest fixture注入 login_page LoginPage(driver) login_page.enter_username(wrong).enter_password(wrong).click_login() error_msg login_page.get_error_message() assert 用户名或密码错误 in error_msg避坑指南Web UI自动化的稳定性强制使用显式等待绝对不要用time.sleep()要用WebDriverWait配合expected_conditions。这是解决元素加载时序问题的银弹。定位器优先级ID Name CSS Selector XPath。XPath尽量少用绝对路径/html/...多用相对路径和属性组合如//button[data-testidsubmit]。失败重试机制利用pytest的pytest.mark.flaky装饰器或pytest-rerunfailures插件对不稳定的用例自动重试1-2次。并行与分布式使用pytest-xdist插件实现用例并行执行能极大缩短UI测试套件的执行时间。2.3 类型三接口自动化测试框架Requests Pytest接口测试是投入产出比最高的自动化测试类型。它执行快、稳定性高、更接近服务端业务逻辑。其核心框架就是“Requests库做HTTP客户端Pytest做测试管理和断言”。为什么Requests是首选Python自带的urllib库比较底层使用繁琐。Requests库的口号是“HTTP for Humans”它的API设计极其优雅直观发送一个GET请求只需要requests.get(url)添加头信息、参数、JSON体都非常简单。它的会话Session对象还能自动管理cookies模拟用户连续请求的行为。接口测试框架的核心架构一个可维护的接口测试框架至少应包含以下层次公共工具层封装HTTP请求方法如send_request、读取配置文件、处理加解密签名等。数据层管理测试数据可以从YAML、JSON、Excel或数据库中读取。业务层封装具体的API调用比如UserAPI类下有login、get_user_info等方法。测试用例层纯测试逻辑调用业务层方法进行断言。实操示例一个带认证和参数化的接口测试# utils/request_client.py import requests from typing import Any, Dict class RequestClient: def __init__(self, base_url): self.session requests.Session() self.base_url base_url def request(self, method, endpoint, **kwargs) - requests.Response: url f{self.base_url}{endpoint} # 可以在这里统一添加headers如认证token if hasattr(self, token): kwargs.setdefault(headers, {}).update({Authorization: fBearer {self.token}}) return self.session.request(method, url, **kwargs) # 便捷方法 def get(self, endpoint, paramsNone, **kwargs): return self.request(GET, endpoint, paramsparams, **kwargs) def post(self, endpoint, dataNone, jsonNone, **kwargs): return self.request(POST, endpoint, datadata, jsonjson, **kwargs) # api/user_api.py from utils.request_client import RequestClient class UserAPI: def __init__(self, client: RequestClient): self.client client def login(self, username, password) - Dict[str, Any]: 登录并返回响应同时将token存入client resp self.client.post(/api/login, json{username: username, password: password}) resp.raise_for_status() data resp.json() self.client.token data.get(token) # 存储token供后续请求使用 return data def get_profile(self): return self.client.get(/api/user/profile).json() # 测试用例 # test_user_api.py import pytest pytest.fixture def api_client(): client RequestClient(base_urlhttps://api.your-app.com) yield client client.session.close() # 测试结束后清理 pytest.fixture def user_api(api_client): return UserAPI(api_client) # 使用pytest的参数化功能批量测试不同登录场景 pytest.mark.parametrize(username, password, expected_code, [ (correct_user, correct_pass, 200), (wrong_user, any_pass, 401), (correct_user, , 400), ]) def test_login(username, password, expected_code, user_api): if expected_code 200: # 测试成功登录 result user_api.login(username, password) assert result[user][name] username assert user_api.client.token is not None # 验证token已设置 else: # 测试失败登录 with pytest.raises(requests.exceptions.HTTPError) as exc_info: user_api.login(username, password) assert exc_info.value.response.status_code expected_code接口测试的关键技巧断言不仅要看状态码更要验证响应体的数据结构、关键字段的值和类型。可以使用jsonschema库来验证响应是否符合预定义的JSON Schema。处理依赖比如测试“下单”接口需要先有“登录”的token和“商品”的ID。可以用pytest的夹具依赖pytest.fixture来管理这种链条。数据驱动将测试用例和测试数据分离。pytest的pytest.mark.parametrize是内置的数据驱动利器也可以结合pytest-excel或pytest-yaml等插件从外部文件读取数据。2.4 类型四移动端自动化测试框架Appium Pytest移动端测试Android/iOS的复杂度比Web更高因为涉及真机/模拟器管理、多系统版本、多屏幕尺寸。Appium是目前最主流的跨平台移动端自动化工具它同样遵循WebDriver协议这意味着如果你熟悉Selenium那么Appium的学习成本会很低。它的核心理念是“一套API测试所有平台Android、iOS”。框架核心Appium Pytest PO模式技术栈和Web UI自动化非常相似只是把Selenium换成了Appium。PO模式在这里同样重要用来封装各个App屏幕Screen或Page。环境搭建的坑与技巧这是移动端自动化最大的拦路虎。你需要安装Appium Server可以通过Node.js的npm安装npm install -g appium也可以直接下载桌面版。建议新手用桌面版带图形界面和元素检查器。配置设备Android安装Android SDK配置ANDROID_HOME环境变量并确保adb命令可用。准备一个真机或启动一个模拟器如Android Studio自带的AVD。iOS需要macOS系统和Xcode配置更复杂。对于iOS真机还需要苹果开发者账号和证书。安装Python客户端pip install Appium-Python-Client。实操示例一个简单的Android App登录测试# conftest.py - 配置Appium驱动夹具 import pytest from appium import webdriver from appium.options.android import UiAutomator2Options pytest.fixture(scopesession) def appium_driver(): # 1. 定义设备能力Desired Capabilities options UiAutomator2Options() options.platform_name Android options.device_name 你的设备名或模拟器名 # 通过adb devices获取 options.app_package com.example.app # 被测App的包名 options.app_activity .MainActivity # 启动Activity options.automation_name UiAutomator2 options.no_reset True # 不重置App状态提升测试速度 # 2. 连接Appium Server driver webdriver.Remote(http://localhost:4723, optionsoptions) yield driver # 3. 测试结束后退出 driver.quit() # screens/login_screen.py from appium.webdriver.common.appiumby import AppiumBy class LoginScreen: # 使用Appium提供的定位方式如ACCESSIBILITY_ID对应content-desc USERNAME_FIELD (AppiumBy.ACCESSIBILITY_ID, username_input) PASSWORD_FIELD (AppiumBy.ID, com.example.app:id/password) LOGIN_BTN (AppiumBy.XPATH, //android.widget.Button[text登录]) def __init__(self, driver): self.driver driver def login(self, username, password): self.driver.find_element(*self.USERNAME_FIELD).send_keys(username) self.driver.find_element(*self.PASSWORD_FIELD).send_keys(password) self.driver.find_element(*self.LOGIN_BTN).click() # 返回下一个页面的对象实现流程串联 from screens.home_screen import HomeScreen return HomeScreen(self.driver) # 测试用例 # test_app_login.py def test_app_login_success(appium_driver): login_screen LoginScreen(appium_driver) home_screen login_screen.login(test_user, password123) # 断言登录成功例如首页某个特定元素出现 welcome_text home_screen.get_welcome_text() assert 欢迎回来 in welcome_text移动端特有问题的解决方案元素定位难优先使用resource-idAndroid或accessibility idiOS它们最稳定。xpath在移动端性能较差慎用。Appium Desktop的Inspector工具是查找元素定位器的必备。等待策略和Web一样使用显式等待。Appium提供了WebDriverWait和移动端特有的预期条件如presence_of_element_located。混合应用与WebView如果App内嵌了H5页面需要切换上下文Context。使用driver.contexts获取所有上下文然后driver.switch_to.context(WEBVIEW_xxx)切换到WebView进行Selenium式的操作操作完再切回NATIVE_APP。并行测试需要启动多个Appium Server实例绑定不同端口并为每个实例分配不同的设备UDID。可以使用pytest-xdist配合自定义夹具来实现。2.5 类型五行为驱动开发BDD框架Behave / Pytest-BDD这种类型侧重于沟通和文档。BDDBehavior-Driven Development让你能用近乎自然语言的格式Gherkin语法编写测试用例业务人员、产品经理也能看懂。它的核心是“将需求规格转化为可执行的测试”。框架选择Behave 还是 Pytest-BDDBehave一个独立的BDD框架功能纯粹社区活跃。它的用例文件.feature和步骤实现.py是分开的结构清晰。Pytest-BDD是pytest的一个插件。如果你已经在用pytest希望将BDD集成到现有的测试工程中那么pytest-bdd是更无缝的选择。它允许你在同一个项目中既写传统的单元测试也写BDD场景。BDD实战一个用户注册场景BDD用例写在.feature文件中使用Gherkin语法Given-When-Then。# features/registration.feature Feature: 用户注册 作为新用户 我希望能够注册账号 以便使用系统的核心功能 Scenario: 成功注册新用户 Given 我打开注册页面 When 我输入有效的用户名 newuser_001 和邮箱 newexample.com 和密码 Pssw0rd And 我点击注册按钮 Then 我应该看到注册成功的提示信息 And 我应该被重定向到个人主页 Scenario: 使用已存在的用户名注册失败 Given 我打开注册页面 When 我输入已存在的用户名 existing_user 和任意邮箱 And 我点击注册按钮 Then 我应该看到错误提示 用户名已存在然后你需要用Python代码来实现这些步骤Step Definitions# features/steps/registration_steps.py from pytest_bdd import scenarios, given, when, then, parsers from pages.register_page import RegisterPage from pages.home_page import HomePage # 绑定feature文件 scenarios(../registration.feature) given(我打开注册页面) def open_register_page(browser): # browser是pytest-bdd注入的fixture类似Selenium driver register_page RegisterPage(browser) register_page.open() return register_page when(parsers.parse(我输入有效的用户名 {username} 和邮箱 {email} 和密码 {password})) def enter_valid_credentials(open_register_page, username, email, password): open_register_page.enter_username(username) open_register_page.enter_email(email) open_register_page.enter_password(password) when(我点击注册按钮) def click_register_button(open_register_page): open_register_page.click_register() then(我应该看到注册成功的提示信息) def see_success_message(browser): home_page HomePage(browser) assert home_page.get_welcome_message() 注册成功欢迎加入我们。 # 实现失败场景的步骤...BDD的适用场景与陷阱适用验收测试、端到端E2E测试、需要与业务方频繁确认需求的场景。它产生的.feature文件本身就是一份活的、可执行的文档。陷阱步骤定义不要过于细粒度比如把“我输入用户名”和“我输入密码”拆成两个步骤会导致步骤定义爆炸维护困难。应该像上面例子一样将一组相关的操作合并到一个有意义的步骤中。不要滥用场景大纲Scenario Outline数据驱动是好的但过度使用会让.feature文件变得难以阅读。复杂的数据准备和清理最好放在步骤定义的代码里处理。BDD不是银弹它不适合用来描述底层、技术性的测试比如某个API的边界值测试。对于单元测试和集成测试传统的pytest写法更简洁高效。3. 框架整合与工程化实践选好了框架类型不等于就有了可用的自动化测试。你需要把它们组织成一个真正的、可维护、可执行的测试项目。这就是工程化要解决的问题。3.1 项目目录结构设计一个清晰的目录结构是维护性的基础。我推荐如下结构your_automation_project/ ├── config/ # 配置文件 │ ├── config.yaml # 主配置环境地址、数据库连接等 │ └── devices.yaml # 移动端设备配置 ├── data/ # 测试数据文件 │ ├── test_data.json │ └── api_data.xlsx ├── logs/ # 日志目录.gitignore ├── reports/ # 测试报告目录.gitignore ├── pages/ 或 screens/ # Page Object / Screen Object │ ├── __init__.py │ ├── login_page.py │ └── home_page.py ├── api/ # 接口封装层 │ ├── __init__.py │ ├── client.py │ └── user_api.py ├── utils/ # 工具函数 │ ├── __init__.py │ ├── logger.py │ └── file_reader.py ├── tests/ # 测试用例 │ ├── ui_tests/ │ │ ├── __init__.py │ │ ├── test_login.py │ │ └── conftest.py # 本地夹具如初始化driver │ ├── api_tests/ │ │ ├── __init__.py │ │ └── test_user_api.py │ └── unit_tests/ │ └── test_models.py ├── features/ # BDD特性文件如果用了BDD │ ├── registration.feature │ └── steps/ │ └── registration_steps.py ├── conftest.py # 全局pytest夹具配置如driver初始化 ├── pytest.ini # pytest配置文件 ├── requirements.txt # Python依赖包列表 └── README.md # 项目说明3.2 核心配置管理pytest.ini与conftest.pypytest.ini用于控制pytest的默认行为。# pytest.ini [pytest] # 指定测试文件搜索路径 testpaths tests # 自动发现以test_开头和结尾的文件和函数 python_files test_*.py python_classes Test* python_functions test_* # 添加命令行默认参数 addopts -v --tbshort --strict-markers # 自定义标记用于分类运行用例 markers smoke: 冒烟测试用例 slow: 执行缓慢的用例 ui: UI自动化测试 api: 接口自动化测试conftest.py是pytest的本地插件文件用于定义夹具fixture这些夹具可以被同一目录及子目录下的所有测试文件使用。这是实现测试数据准备、环境初始化的核心。# conftest.py import pytest import yaml from selenium import webdriver from appium import webdriver as appium_driver from utils.request_client import RequestClient # 读取全局配置 def load_config(): with open(config/config.yaml, r, encodingutf-8) as f: return yaml.safe_load(f) pytest.fixture(scopesession) def config(): 全局配置夹具 return load_config() pytest.fixture(scopefunction) # 每个测试函数执行一次 def browser(config): Web UI测试的driver夹具 options webdriver.ChromeOptions() if config[headless]: options.add_argument(--headless) driver webdriver.Chrome(optionsoptions) driver.implicitly_wait(config[implicit_wait]) driver.maximize_window() yield driver # 测试结束后无论成功失败都退出浏览器 driver.quit() pytest.fixture(scopesession) def api_client(config): 接口测试的客户端夹具 client RequestClient(base_urlconfig[api][base_url]) yield client client.session.close() pytest.fixture(scopefunction) def login_user(api_client): 一个依赖其他夹具的夹具预先登录一个用户 user_api UserAPI(api_client) user_api.login(config[test_user][name], config[test_user][pass]) return user_api # 将已登录的api对象提供给测试用例3.3 测试报告与持续集成自动化测试如果不集成到开发流程中价值就大打折扣。Allure报告和Jenkins/GitLab CI是黄金组合。生成Allure测试报告安装pip install allure-pytest。运行测试时添加参数pytest --alluredir./reports/allure_raw。生成可查看的HTML报告allure generate ./reports/allure_raw -o ./reports/allure_html --clean。在conftest.py或用例中可以通过allure.title、allure.story、allure.severity等装饰器来美化报告还可以通过allure.attach附加截图、日志等。集成到Jenkins Pipeline在Jenkins中创建一个Pipeline项目配置Jenkinsfilepipeline { agent any stages { stage(Checkout) { steps { git branch: main, url: 你的Git仓库地址 } } stage(Setup) { steps { sh python -m pip install --upgrade pip sh pip install -r requirements.txt } } stage(Test) { steps { sh pytest tests/ --alluredir./reports/allure_raw } } stage(Report) { steps { allure includeProperties: false, jdk: , results: [[path: ./reports/allure_raw]] } } } post { always { // 可选测试失败时发送通知 } } }这样每次代码提交后Jenkins会自动拉取代码、安装依赖、执行测试并生成漂亮的Allure报告。报告里会清晰展示通过率、失败用例、错误日志和截图问题定位效率极大提升。4. 常见问题与排查技巧实录在实际落地过程中你一定会遇到各种“坑”。这里记录了几个最常见的问题和我的解决思路。4.1 Web UI自动化元素找不到NoSuchElementException这是UI自动化中最常见的问题没有之一。可能原因1页面加载慢元素还没出现。解决方案彻底放弃隐式等待和time.sleep()全面使用显式等待WebDriverWait。将所有的find_element操作都包裹在等待条件中。代码示例from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 错误做法 # element driver.find_element(By.ID, “dynamic_button”) # 正确做法 wait WebDriverWait(driver, 10) # 最多等10秒 element wait.until(EC.element_to_be_clickable((By.ID, “dynamic_button”))) element.click()可能原因2元素在iframe或shadow DOM里。解决方案对于iframe必须先切换到对应的frame中才能操作元素操作完再切回。driver.switch_to.frame(“frame_name_or_id”) # 切换到iframe # 操作iframe内的元素 driver.switch_to.default_content() # 切回主文档对于Shadow DOMSelenium 4提供了新的API支持需要使用driver.execute_script或专门的shadow_root属性来穿透。可能原因3元素定位器写错了或者页面结构变了。解决方案使用浏览器开发者工具F12的“检查”功能重新确认元素的唯一属性。优先使用id、name、>pytest.fixture def test_user(api_client): 创建一个临时用户测试后删除 user_api UserAPI(api_client) user_data user_api.create_user(generate_unique_username()) yield user_data # 将用户数据提供给测试用例 # 测试用例执行完毕后执行清理 user_api.delete_user(user_data[id])使用测试环境与数据隔离为自动化测试准备独立的数据库或环境并定期如每晚通过脚本重置数据基线。使用工厂模式生成数据使用factory_boy或faker库动态生成测试数据确保每次运行的数据都是新的避免冲突。4.3 移动端自动化设备管理与稳定性问题1Appium Server连接失败或会话创建超时。排查首先检查Appium Server是否启动默认端口4723。然后检查设备是否连接adb devices。最后检查Desired Capabilities中的appPackage和appActivity是否正确对于Android可以用adb shell dumpsys window | grep mCurrentFocus查看当前Activity。问题2在真机上运行缓慢或不稳定。技巧设置options.no_reset True和options.fullReset False避免每次测试都重装App。关闭动画以提高速度在开发者选项里关闭“窗口动画缩放”、“过渡动画缩放”、“动画程序时长调整”。对于iOS使用settings[snapshotTimeout] 10等设置来调整超时。使用driver.background_app(seconds)来模拟App切换到后台再回来的场景而不是每次都重启。4.4 测试用例设计可读性与可维护性反模式一个测试函数里塞了十几个步骤既测登录又测浏览商品又测下单断言混杂。最佳实践遵循“单一职责”和“原子性”原则。一个测试函数只验证一件事比如test_login_with_valid_credentialstest_login_with_invalid_password。使用清晰的夹具名和用例名夹具名如logged_in_user用例名如test_add_item_to_cart_as_logged_in_user让人一眼就知道在测什么。断言要精准断言错误信息时用assert “用户名错误” in error_msg而不是assert error_msg ! “”。使用pytest的assert语句它能给出更丰富的失败信息。善用标记mark用pytest.mark.smoke标记冒烟测试用例用pytest.mark.ui标记UI测试。这样可以通过pytest -m smoke只运行冒烟用例pytest -m “not slow”跳过慢速用例。自动化测试是一个需要持续投入和优化的工程。它不是一个一蹴而就的项目而是一个伴随产品迭代不断演进的系统。从选择适合自己团队的框架类型开始搭建一个结构清晰、易于维护的项目再通过持续集成将其融入到开发流程中才能真正发挥其价值把测试人员从重复劳动中解放出来去关注更重要的测试设计和质量分析。