pytest中Mocha钩子等价实现及API测试数据初始化方案咨询
pytest 对应 Mocha 钩子的等价实现
Mocha 的四个核心钩子在 pytest 中有直接的等价实现,对应关系如下:
- Mocha
before→ pytestsetup_module函数或scope="module"的 fixturesetup_module是模块级前置逻辑,在当前.py文件所有测试用例执行前仅运行一次,适合初始化模块级共享资源。
示例:
def setup_module(module): # 模块级前置操作:比如加载全局配置、初始化API会话 print("所有测试用例执行前运行一次") - Mocha
beforeEach→ pytestsetup_function函数或默认scope="function"的 fixturesetup_function在每个测试函数执行前运行,适合初始化单个用例的专属数据。
示例:
def setup_function(func): # 用例级前置操作:比如创建临时测试数据 print(f"测试用例 {func.__name__} 执行前运行") - Mocha
after→ pytestteardown_module函数或scope="module"的 fixture(通过yield实现后置)teardown_module在模块所有用例执行完成后仅运行一次,用于清理模块级资源。
示例:
def teardown_module(module): # 模块级后置操作:比如关闭全局会话、清理共享数据 print("所有测试用例执行后运行一次") - Mocha
afterEach→ pytestteardown_function函数或默认scope="function"的 fixture(通过yield实现后置)teardown_function在每个测试函数执行完成后运行,用于清理单个用例的临时数据。
示例:
def teardown_function(func): # 用例级后置操作:比如删除临时测试数据 print(f"测试用例 {func.__name__} 执行后运行")
API测试前置需求的解决方案
针对你需要的「模块执行前运行脚本」「每个测试用例前初始化测试数据」的需求,除了 fixture 外,还有以下实用方案:
1. 直接使用 setup/teardown 系列函数
这是最直观的方式,完全匹配你的需求场景:
- 模块级前置:用
setup_module做全局初始化(比如加载API配置、创建全局请求会话、获取全局token) - 用例级前置:用
setup_function做单个用例的测试数据初始化(比如创建临时用户、生成专属测试资源)
示例代码:
import requests # 模块级前置:初始化全局API会话 def setup_module(module): module.session = requests.Session() module.base_url = "https://api.example.com/v1" # 登录获取全局token login_res = module.session.post(f"{module.base_url}/login", json={"username": "test", "password": "123456"}) module.session.headers["Authorization"] = f"Bearer {login_res.json()['token']}" # 用例级前置:每个用例前创建临时测试用户 def setup_function(func): create_user_res = session.post(f"{base_url}/users", json={"name": "temp_user"}) func.test_user_id = create_user_res.json()["id"] # 测试用例 def test_get_user_detail(): res = session.get(f"{base_url}/users/{test_get_user_detail.test_user_id}") assert res.status_code == 200 assert res.json()["name"] == "temp_user"
2. 自定义测试基类(面向对象风格)
如果习惯用类组织测试用例,可以编写一个基类封装前置逻辑,测试类继承后直接复用:
示例代码:
import requests import pytest class BaseAPITest: session = None base_url = "https://api.example.com/v1" @classmethod def setup_class(cls): # 类级前置:所有类内测试用例执行前运行一次 cls.session = requests.Session() login_res = cls.session.post(f"{cls.base_url}/login", json={"username": "test", "password": "123456"}) cls.session.headers["Authorization"] = f"Bearer {login_res.json()['token']}" def setup_method(self): # 方法级前置:每个测试方法执行前运行 create_user_res = self.session.post(f"{self.base_url}/users", json={"name": "temp_user"}) self.test_user_id = create_user_res.json()["id"] class TestUserAPI(BaseAPITest): def test_get_user(self): res = self.session.get(f"{self.base_url}/users/{self.test_user_id}") assert res.status_code == 200 def test_delete_user(self): res = self.session.delete(f"{self.base_url}/users/{self.test_user_id}") assert res.status_code == 204
补充:Fixture 其实可以控制传入数据
你提到觉得 fixture 无法控制传入数据,其实可以通过工厂模式或参数化实现动态传参:
工厂模式 fixture(动态传入自定义数据)
import pytest import requests @pytest.fixture(scope="module") def api_session(): session = requests.Session() base_url = "https://api.example.com/v1" login_res = session.post(f"{base_url}/login", json={"username": "test", "password": "123456"}) session.headers["Authorization"] = f"Bearer {login_res.json()['token']}" yield session @pytest.fixture def create_test_user(api_session): # 返回一个工厂函数,允许传入自定义参数 def _create_user(name="temp_user"): res = api_session.post(f"{base_url}/users", json={"name": name}) return res.json()["id"] return _create_user # 测试用例中传入自定义用户名 def test_get_custom_user(create_test_user): user_id = create_test_user(name="my_custom_user") res = api_session.get(f"{base_url}/users/{user_id}") assert res.json()["name"] == "my_custom_user"
参数化 fixture(批量测试不同数据)
@pytest.fixture(params=["user1", "user2", "user3"]) def test_user_name(request): return request.param def test_create_user(api_session, test_user_name): res = api_session.post(f"{base_url}/users", json={"name": test_user_name}) assert res.json()["name"] == test_user_name
内容的提问来源于stack exchange,提问作者Mona101ma
相关产品推荐
相关产品推荐

