必须在conftest.py中显式调用pytest_factoryboy.register(userfactory),注册后自动生成小写下划线命名的fixture(如user_factory);不注册则无法被pytest识别,导致fixture未找到或静默失败。

直接结论:pytest-factoryboy 不是“拿来即用”的黑盒,它必须配合 factory_boy 工厂类注册 + pytest fixture 命名约定才能生效;漏掉 register 或写错 factory__name 字段路径,测试会静默失败或报 fixture 'xxx' not found。
如何让工厂类被 pytest-factoryboy 自动识别为 fixture?
pytest-factoryboy 不会自动扫描所有 Factory 子类。你必须显式注册——否则 UserFactory 再完整,@pytest.mark.parametrize 里也调不到它。
- 在
conftest.py中调用pytest_factoryboy.register(UserFactory),这是唯一生效方式 - 注册后,
UserFactory会自动变成名为user_factory的 fixture(小写下划线命名,不是类名原样) - 若想改 fixture 名,用
pytest_factoryboy.register(UserFactory, "admin_user"),之后就能用def test_xxx(admin_user): - 多个工厂要逐个注册,不支持通配符或模块级批量注册
为什么 user__email 这种嵌套字段能覆盖关联对象属性?
这是 pytest-factoryboy 的核心语法糖,本质是把双下划线 __ 解析为 SubFactory 层级路径。它只对已声明 SubFactory 的字段有效,不是通用字典展开。
- 前提:你的
OrderFactory必须定义customer = factory.SubFactory(UserFactory) - 然后才能在测试中写
OrderFactory(customer__email="test@x.com"),它会透传到UserFactory(email="test@x.com") - 如果误写成
order__email(但OrderFactory没定义order字段),pytest 会报AttributeError: 'OrderFactory' object has no attribute 'order' - 注意:不能跨两级,比如
order__customer__email是无效的,最多一级__
使用 .create() 还是 .build()?ORM 场景下必须选对
factory_boy 默认构建策略是 build()(内存对象),但 pytest-factoryboy 注册后的 fixture 默认走 create()(持久化到 DB)。这个隐式行为容易引发事务冲突。
- Django/SQLAlchemy 测试中,若你已用
@pytest.fixture(scope="function")控制事务回滚,再用create()就没问题 - 但如果测试函数里手动调用了
UserFactory.create(),而 fixture 又触发了一次create(),会导致重复插入、主键冲突或外键约束失败 - 安全做法:统一用 fixture(即
user_factory),它由 pytest-factoryboy 管理生命周期;避免在测试体内混用.create()和.build() - 真需要内存对象时,显式调用
UserFactory.build(),但此时它不会触发数据库操作,也不受事务 fixture 管理
最容易被忽略的是工厂注册的时机和位置:必须放在 conftest.py 中,且 import 顺序要确保工厂类已加载——放在 import pytest_factoryboy 之后,但在任何测试函数执行之前。否则注册失效,后续所有依赖都静默降级为普通 factory_boy 调用,失去 fixture 注入能力。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











