以下是pytest中fixture的 4 个具体使用案例,涵盖不同应用场景。
案例1:基本 fixture —— 提供测试数据
# test_fixture_basic.pyimportpytest@pytest.fixturedefsample_data():"""返回一个字典作为测试数据"""return{"name":"Alice","age":30}deftest_user_info(sample_data):assertsample_data["name"]=="Alice"assertsample_data["age"]==30案例2:fixture 作用域 —— 控制生命周期
# test_fixture_scope.pyimportpytestimporttime@pytest.fixture(scope="session")defshared_resource():"""整个测试会话只创建一次"""print("\n[setup] 创建共享资源(耗时操作)")resource={"data":[1,2,3]}yieldresourceprint("\n[teardown] 释放共享资源")deftest_one(shared_resource):assertshared_resource["data"]==[1,2,3]deftest_two(shared_resource):assertlen(shared_resource["data"])==3运行pytest -s可看到 setup/teardown 只执行一次。
案例3:fixture 依赖另一个 fixture
# test_fixture_dependency.pyimportpytest@pytest.fixturedefuser():return{"id":1,"name":"Bob"}@pytest.fixturedefuser_with_email(user):"""依赖 user fixture,扩展数据"""user["email"]="bob@example.com"returnuserdeftest_user_email(user_with_email):assertuser_with_email["name"]=="Bob"assertuser_with_email["email"]=="bob@example.com"案例4:使用yield实现 teardown(资源清理)
# test_fixture_teardown.pyimportpytestimporttempfileimportos@pytest.fixturedeftemp_file():"""创建临时文件,测试后自动删除"""f=tempfile.NamedTemporaryFile(delete=False)f.write(b"pytest data")f.close()yieldf.name# 将文件路径传给测试函数# teardown 部分os.unlink(f.name)print(f"\n已删除临时文件{f.name}")deftest_temp_file_content(temp_file):withopen(temp_file,"rb")asf:content=f.read()assertcontent==b"pytest data"运行方式:
保存任意.py文件,执行pytest 文件名.py -v(加-s可看到 print 输出)。
补充说明:
- 默认 fixture 作用域为
function(每个测试函数独立) - 可使用
autouse=True让 fixture 自动生效(无需显式引用) - 通过
pytest.mark.usefixtures可在类或模块级别引用多个 fixture
在unittest框架中,虽然没有像pytest那样独立且高度灵活的@pytest.fixture装饰器,但它内置了一套名为xUnit风格的 fixture 机制。这套机制通过预定义的方法钩子来实现测试前后的准备和清理工作。
⚙️ unittest 中的“Fixture”核心方法
以下是unittest中实现 Fixture 的核心方法,它们作用于不同层级,共同构成了测试的环境管理:
| 层级 | 方法 | 执行时机 | 适用场景 |
|---|---|---|---|
| 方法级 | setUp(self) | 每个测试方法执行前 | 为每个测试准备独立的环境,如创建临时对象、重置变量状态 |
tearDown(self) | 每个测试方法执行后 | 清理每个测试产生的临时数据,如关闭网络连接、清空列表 | |
| 类级 | setUpClass(cls) | 整个测试类的所有方法执行前执行一次 | 执行一次性的、开销较大的准备工作,如建立数据库连接池、加载配置 |
tearDownClass(cls) | 整个测试类的所有方法执行后执行一次 | 清理类级别的资源,如断开数据库连接池 | |
| 模块级 | setUpModule() | 整个模块文件中的所有测试执行前执行一次 | 进行模块级的全局环境配置,如设置系统环境变量、启动一个全局服务 |
tearDownModule() | 整个模块文件中的所有测试执行后执行一次 | 清理模块级的全局资源,如停止全局服务 |
注意:
setUpClass和tearDownClass是类方法,必须使用@classmethod装饰器。setUpModule和tearDownModule是模块级别的函数,需直接定义在测试文件中。
📝 核心Fixture使用案例
以下示例演示了setUp(),tearDown(),setUpClass(),tearDownClass()和addCleanup()的使用。
importunittestimportosimporttempfileclassTestMathOperations(unittest.TestCase):@classmethoddefsetUpClass(cls):"""整个测试类只执行一次"""print("\n[setUpClass] 初始化类级资源")# 例如:创建数据库连接池cls.db_pool="Mock DB Pool"cls.shared_value=42@classmethoddeftearDownClass(cls):"""整个测试类只执行一次"""print("[tearDownClass] 清理类级资源")cls.db_pool=NonedefsetUp(self):"""每个测试方法执行前都会执行"""print(f"\n[setUp] 为测试 '{self._testMethodName}' 准备环境")self.temp_file=tempfile.NamedTemporaryFile(delete=False)self.temp_file.write(b"test data")self.temp_file.close()# 使用 addCleanup 确保临时文件被删除,即使测试失败也会执行self.addCleanup(os.remove,self.temp_file.name)deftearDown(self):"""每个测试方法执行后都会执行"""print(f"[tearDown] 清理测试 '{self._testMethodName}' 的环境")# 这里可以进行一些常规清理,但注意文件清理已由 addCleanup 处理deftest_addition(self):print(" 执行测试: test_addition")result=1+1self.assertEqual(result,2)deftest_subtraction(self):print(" 执行测试: test_subtraction")result=5-3self.assertEqual(result,2)deftest_shared_resource(self):"""演示使用类级共享资源"""print(f" 执行测试: test_shared_resource, 共享值:{self.shared_value}")self.assertEqual(self.shared_value,42)if__name__=='__main__':unittest.main()运行这个测试,你将在控制台看到清晰的执行顺序,直观理解各钩子方法的调用时机。
💎 总结:pytestFixture vs.unittestFixture
| 特性 | pytestFixture | unittestFixture |
|---|---|---|
| 实现方式 | 使用@pytest.fixture装饰器声明,高度解耦 | 继承unittest.TestCase并重写预定义的钩子方法 |
| 灵活性 | 极高,支持依赖注入、参数化、多种作用域 | 较低,遵循固定的setUp/tearDown模式 |
| 代码重用 | 简单,Fixture 可跨文件、跨项目共享 | 较复杂,通常需要通过继承 TestCase 基类来复用 |
| 作用域 | 支持function,class,module,package,session | 通过setUp/tearDown(方法)、setUpClass/tearDownClass(类)、setUpModule/tearDownModule(模块) 实现三级作用域 |
| 清理机制 | yield语句后编写清理代码,简洁直观 | 通过tearDown和addCleanup实现 |
| 学习曲线 | 稍陡,但概念统一,掌握后效率极高 | 平缓,结构固定,易于理解和入门 |
unittest的 Fixture 机制简单直接,对于基础的项目测试而言,它的setUp和tearDown方法已经足够清晰和有效。不过,如果你追求更灵活的测试组织、更高效的资源共享,pytest的 fixture 会是更强大的选择。