Pytest如何使用生成器替代mark.parametrize实现MongoDB大数据集测试
解决方案
该需求完全可以实现,核心思路是避免在Pytest的测试收集阶段加载全量数据,改用运行时流式拉取MongoDB游标数据的方式执行测试,常用的两种实现方案如下:
方案1:单测试用例内迭代游标(最简单、内存占用最低)
直接在测试函数内部遍历pymongo的Cursor对象,pymongo默认会分批拉取数据(默认首批拉取101条或16MB,后续批次自动加载),不会一次性加载全量集合数据到内存。
def test_all_docs(): # 直接获取游标,不会立刻拉取全量数据 cursor = db["collection"].find({}) for doc in cursor: # 断言时补充文档ID作为错误提示,方便定位异常数据 assert doc["val"] == 1, f"文档{doc['_id']}校验失败,val字段实际值为:{doc['val']}"
- 优点:代码无额外依赖,实现成本极低,内存占用稳定在极低水平
- 缺点:单条数据校验失败后默认会终止测试,若需要跑完所有数据可额外捕获异常并统一汇总错误
方案2:使用subtests子测试功能(每条数据作为独立测试项统计)
如果需要每条文档的测试结果独立统计(直观看到总共有多少条通过/失败,单条失败不影响后续测试执行),可以用Pytest内置的subtests上下文管理器:
import pytest def test_all_docs(): cursor = db["collection"].find({}) for idx, doc in enumerate(cursor): # 子测试标识可以自定义,此处配置了序号和文档ID方便定位 with pytest.subtest(test_idx=idx, doc_id=doc["_id"]): assert doc["val"] == 1 # 其他测试逻辑
- 优点:每条数据的测试结果独立展示,单条失败不会中断整体测试,内存占用同样极低
- 缺点:子测试的统计逻辑和标准参数化测试略有区别,需要在日志中查看单条子测试的结果
为什么原parametrize方案不可行
Pytest的测试收集阶段需要提前确定所有测试用例的参数,因此会自动把@pytest.mark.parametrize传入的可迭代对象转换为列表存储在内存中,对于体量极大的集合会出现收集慢、内存溢出的问题,无法直接使用。
内容的提问来源于stack exchange,提问作者tHeReaver
相关产品推荐
相关产品推荐

