测试用例相互污染源于共享可变全局状态,应通过函数级fixture、隔离外部依赖、显式清理和禁用隐式共享来避免。

测试用例相互污染,通常是因为共享了可变的全局状态、类变量、单例对象、缓存、数据库连接或文件系统资源。避免的关键是让每个测试用例运行在独立、可预测、可重置的环境中。
使用函数作用域的 fixture 替代模块/类级状态
pytest 中默认的 function 作用域 fixture 是最安全的选择。避免在 module 或 class 级别初始化可变对象(如列表、字典、Mock 实例),否则前一个测试修改它会影响后一个测试。
- ✅ 正确:每次测试都新建一个空字典或干净的 Mock
- ❌ 错误:用
@pytest.fixture(scope="module")返回一个被多次.append()的列表
隔离外部依赖:用 patch 或临时实例代替真实调用
数据库、HTTP 请求、文件读写等容易残留副作用。应统一用 unittest.mock.patch(pytest 可配合 monkeypatch)拦截,或为测试构造轻量临时实例(如 sqlite:///:memory: 数据库)。
- 对全局配置:用
monkeypatch.setattr临时修改,退出时自动还原 - 对模块级函数:用
@patch("module.func")装饰器确保隔离 - 避免在
setUp中直接调用requests.get或open()
显式清理 + 使用 teardown 机制
即使用了 fixture,涉及资源申请(如启动线程、创建临时目录、注册信号处理器)时,必须配对清理。pytest 推荐用 yield-fixture;unittest 推荐在 tearDown 中释放。
立即学习“Python免费学习笔记(深入)”;
- yield-fixture 示例:
yield tmpdir; shutil.rmtree(tmpdir) - 避免只在
setUp创建资源却不保证tearDown执行(可用addCleanup注册回调) - 对数据库:每个测试用独立 schema 或事务 rollback,而非共用一张表
禁用隐式共享状态:检查常见“陷阱”
有些看似无害的操作实则引入跨测试污染:
-
日志配置:
logging.basicConfig()全局生效,应改用logging.getLogger().handlers = []重置 -
缓存装饰器:如
@lru_cache或自定义缓存字典,测试前需func.cache_clear() -
单例类:测试中若调用
Singleton.get_instance(),需在 teardown 中重置内部实例变量 -
os.environ:用
monkeypatch.setenv/delenv,别直接赋值










