pytest测试应与业务代码解耦:测试文件独立置于tests/目录,显式导入src模块,用pytest.raises校验异常,patch按被测代码内import路径进行,避免慢速fixture污染全局状态。

pytest 里怎么组织测试用例才不会和业务代码耦合
测试代码和业务逻辑混在一起,改个函数名就满屏红,不是测试写得少,是结构没划清边界。
核心原则:测试文件路径、模块命名、导入方式,全部独立于 src 或 app 目录。推荐项目结构:
myproject/ ├── src/ │ └── mypkg/ │ └── core.py ├── tests/ │ └── test_core.py
- 测试文件必须放在单独的
tests/根目录下,不嵌套进src -
test_core.py里用from src.mypkg.core import do_something显式导入,别用相对导入或修改sys.path - 运行时用
pytest tests/,而非cd src && pytest ../tests—— 后者容易让 Python 把src当成包,引发重复导入或ImportError - 如果用了
pyproject.toml,加一行pythonpath = ["src"],比手动改PYTHONPATH更稳定
assert 和 pytest.raises 怎么选才不掩盖真实错误
用 assert 检查异常信息,看似省事,实则把 AttributeError、KeyError 全吞成 AssertionError,调试时根本看不出哪行崩了。
- 验证是否抛出异常,只用
pytest.raises(ExpectedError)上下文管理器,别写assert "not found" in str(e) - 要检查异常属性(比如
e.code == 404),在with pytest.raises(HttpError) as excinfo:之后取excinfo.value.code - 避免
try/except+assert False这种写法 —— 它会让 pytest 误判为“测试通过”,实际是跳过了异常校验 - 如果函数本不该抛异常,但你写了
pytest.raises(Exception),等于主动屏蔽所有问题,不如直接调用后让测试自然 fail
mock.patch 为什么总 patch 不到,明明路径写对了
patch 的路径必须是「被测试对象内部 import 的位置」,不是定义位置,也不是你 import 的位置 —— 这点错一点全盘失效。
MediPro乡镇政府门户网站系统,适合乡镇政府机构创建地方门户网站,用以宣传本地资源,实现政务公开,促进乡镇基层信息化建设。本系统基于PHP+MYSQL开发,预设了乡镇风采、党政机构、政务公开、投资指南、服务导航、文件下载、公众互动、领导信箱等乡镇政府门户网站常用的栏目和测试数据,采用适合乡镇政府门户网站的专用模版,增强了系统的针对性和易用性。除了文章系统、图文系统、下载系统、社区交流、反馈表单
立即学习“Python免费学习笔记(深入)”;
- 假设
src.mypkg.api.call_external()里写了import requests,那你得在测试里@patch("src.mypkg.api.requests"),而不是@patch("requests")或@patch("src.mypkg.api.call_external.requests") - 用
autospec=True能提前暴露 mock 方法签名不匹配的问题,比如原函数接收 3 个参数,你调用时只传 2 个,它会立刻报错,而不是静默失败 - 别在
setup_method里 patch 然后忘掉stop()—— 多个测试间会互相污染,优先用装饰器或上下文管理器 - 如果被 patch 对象是类方法,确认你 patch 的是类本身(
"src.mypkg.service.MyClient"),不是实例方法名
测试慢、CI 卡住,哪些 fixture 实际上在拖后腿
数据库连接、HTTP 请求、随机 sleep —— 这些不该出现在单元测试里,但很多人把 @pytest.fixture(scope="session") 当成“只跑一次”的免检通行证。
-
scope="session"的 fixture 会在整个 pytest 进程中存活,一旦里面开了 DB 连接又没 close,后续测试可能因连接数超限失败 - 真正需要共享状态的(如测试用 SQLite 文件),用
tmp_path_factory创建临时路径,测试结束自动清理,别复用真实环境路径 - 带网络请求的 fixture(比如预热缓存)必须加
pytest.mark.network标签,并在 CI 中默认跳过,本地可选执行 - 如果某个 fixture 返回的是全局单例(如
logging.getLogger()),记得在每个测试后重置其状态,否则日志断言会串扰
最难的不是写测试,是判断哪段逻辑该测、哪段该绕开、哪段必须隔离 —— 很多“测试难维护”其实是边界没划清楚,而不是工具不会用。










