polyfactory
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesepolyfactory
polyfactory
Polyfactory is a typed mock-data factory library: declare (or , , , ) and returns a fully-populated, validation-passing instance of . Because the factory inspects the model's annotations and constraints, generated data already respects ranges, Pydantic constraints, and attrs validators — no additional fixtures needed for happy-path tests.
ModelFactory[T]DataclassFactoryMsgspecFactoryAttrsFactoryTypedDictFactory.build()Tmsgspec.MetaFieldIn Litestar projects, polyfactory's pytest plugin is the canonical way to feed / payloads. The companion skill covers the request side.
TestClient.post(...)AsyncTestClient.put(...)litestar:litestar-testingPolyfactory是一个类型化模拟数据工厂库:声明(或、、、)后,调用会返回一个完全填充且通过验证的实例。由于工厂会检查模型的注解和约束,生成的数据天然符合范围、Pydantic 约束以及attrs验证器——快乐路径测试无需额外夹具。
ModelFactory[T]DataclassFactoryMsgspecFactoryAttrsFactoryTypedDictFactory.build()Tmsgspec.MetaField在Litestar项目中,polyfactory的pytest插件是为 / 提供负载数据的标准方式。配套技能涵盖请求侧相关内容。
TestClient.post(...)AsyncTestClient.put(...)litestar:litestar-testingCode Style Rules
代码风格规则
- PEP 604 unions: , never
T | None.Optional[T] - rule — Modules that define factory subclasses with introspected
from __future__ import annotationsconfig (Meta,__model__,__random_seed__) are library-like and SHOULD avoid future annotations on the factory module itself if the model class is also defined there. Test modules that use factories (call__set_as_default_factory_for_type__, register fixtures) MAY and typically SHOULD use future annotations — they are pure consumer code. The same rule applies as msgspec/dishka/SAQ..build() - One factory per model. Don't reuse a factory across unrelated models — clarity beats DRY when the test fails at 3am.
- Pick the right factory base by backend: (Pydantic),
ModelFactory,DataclassFactory,MsgspecFactory,AttrsFactory. The wrong base silently degrades to attribute-by-attribute introspection and produces lower-quality data.TypedDictFactory - Prefer over hand-rolled
register_fixturewrappers — it gives you both the fixture and the factory class with one decorator.@pytest.fixture
- PEP 604联合类型:使用,绝不使用
T | None。Optional[T] - 规则——如果模块定义了带有可自省
from __future__ import annotations配置(Meta、__model__、__random_seed__)的工厂子类,且模型类也定义在该模块中,那么这类模块属于类库性质,应避免在工厂模块本身使用future annotations。而使用工厂的测试模块(调用__set_as_default_factory_for_type__、注册夹具)可以且通常应该使用future annotations——它们是纯消费代码。该规则与msgspec/dishka/SAQ的规则一致。.build() - 一个模型对应一个工厂。不要在不相关的模型之间复用工厂——当测试在凌晨3点失败时,清晰性比DRY原则更重要。
- 根据后端选择正确的工厂基类:(Pydantic)、
ModelFactory、DataclassFactory、MsgspecFactory、AttrsFactory。错误的基类会静默退化为逐属性自省,生成的数据质量更低。TypedDictFactory - 优先使用而非手动编写的
register_fixture包装器——它只需一个装饰器就能同时提供夹具和工厂类。@pytest.fixture
Quick Reference
快速参考
Picking the right factory base
选择合适的工厂基类
| Model kind | Factory base | Import |
|---|---|---|
| | |
| | |
| | |
| | |
| | |
| Beanie / Odmantic / SQLA | dedicated bases | see factories.md |
| 模型类型 | 工厂基类 | 导入语句 |
|---|---|---|
| | |
| | |
| | |
| | |
| | |
| Beanie / Odmantic / SQLA | 专用基类 | 参见factories.md |
Defining a factory
定义工厂
python
from dataclasses import dataclass
from polyfactory.factories import DataclassFactory
@dataclass
class Order:
id: int
customer_email: str
total_cents: int
status: str
class OrderFactory(DataclassFactory[Order]):
__model__ = Orderpython
from dataclasses import dataclass
from polyfactory.factories import DataclassFactory
@dataclass
class Order:
id: int
customer_email: str
total_cents: int
status: str
class OrderFactory(DataclassFactory[Order]):
__model__ = OrderUse it
使用示例
one = OrderFactory.build()
many = OrderFactory.batch(10)
`build()` returns a single populated instance. `batch(n)` returns `list[T]` of size `n`. `coverage()` yields one instance per Union/Optional branch — useful for parametrized tests across discriminated unions.one = OrderFactory.build()
many = OrderFactory.batch(10)
`build()`返回单个填充后的实例。`batch(n)`返回大小为`n`的`list[T]`。`coverage()`会为每个Union/Optional分支生成一个实例——在判别联合的参数化测试中非常有用。Customizing fields
自定义字段
python
from polyfactory import Use
from polyfactory.factories import DataclassFactory
class OrderFactory(DataclassFactory[Order]):
__model__ = Order
# Plain literal — every build returns this exact value
status = "pending"
# Callable — re-evaluated per build
customer_email = Use(lambda: "test@example.com")
# Random choice — re-evaluated per build
total_cents = Use(DataclassFactory.__random__.randint, 100, 10_000)Use(callable, *args, **kwargs)build()python
from polyfactory import Use
from polyfactory.factories import DataclassFactory
class OrderFactory(DataclassFactory[Order]):
__model__ = Order
# 纯字面量——每次构建都返回该精确值
status = "pending"
# 可调用对象——每次构建都会重新计算
customer_email = Use(lambda: "test@example.com")
# 随机选择——每次构建都会重新计算
total_cents = Use(DataclassFactory.__random__.randint, 100, 10_000)Use(callable, *args, **kwargs)build()Determinism
确定性
python
class OrderFactory(DataclassFactory[Order]):
__model__ = Order
__random_seed__ = 42 # same seed → same output across runsSet (or for finer Faker control) when test assertions depend on the exact generated values.
__random_seed____faker__ = Faker(seed=...)python
class OrderFactory(DataclassFactory[Order]):
__model__ = Order
__random_seed__ = 42 # 相同种子→多次运行输出一致当测试断言依赖于精确生成的值时,设置(或以获得更精细的Faker控制)。
__random_seed____faker__ = Faker(seed=...)Default factory registration
默认工厂注册
python
class CustomerFactory(DataclassFactory[Customer]):
__model__ = Customer
__set_as_default_factory_for_type__ = True
@dataclass
class Order:
id: int
customer: Customer # automatically populated by CustomerFactory.build()
class OrderFactory(DataclassFactory[Order]):
__model__ = OrderWhen , polyfactory uses that factory whenever the type appears as a field on another model — no manual nesting required.
__set_as_default_factory_for_type__ = Truepython
class CustomerFactory(DataclassFactory[Customer]):
__model__ = Customer
__set_as_default_factory_for_type__ = True
@dataclass
class Order:
id: int
customer: Customer # 自动由CustomerFactory.build()填充
class OrderFactory(DataclassFactory[Order]):
__model__ = Order当时,只要该类型作为其他模型的字段出现,polyfactory就会使用该工厂——无需手动嵌套。
__set_as_default_factory_for_type__ = TruePytest fixture from a factory
从工厂创建pytest夹具
python
import pytest
from polyfactory.pytest_plugin import register_fixture
from polyfactory.factories import DataclassFactory
@register_fixture
class OrderFactory(DataclassFactory[Order]):
__model__ = Order
def test_order_total(order_factory: OrderFactory) -> None:
order = order_factory.build()
assert order.total_cents >= 0@register_fixtureOrderFactorypython
import pytest
from polyfactory.pytest_plugin import register_fixture
from polyfactory.factories import DataclassFactory
@register_fixture
class OrderFactory(DataclassFactory[Order]):
__model__ = Order
def test_order_total(order_factory: OrderFactory) -> None:
order = order_factory.build()
assert order.total_cents >= 0@register_fixtureOrderFactoryCross-model relationships
跨模型关系
python
import pytest
from polyfactory import Use
from polyfactory.pytest_plugin import register_fixture
@register_fixture
class CustomerFactory(DataclassFactory[Customer]):
__model__ = Customer
__set_as_default_factory_for_type__ = True
@register_fixture
class OrderFactory(DataclassFactory[Order]):
__model__ = Order
customer = Use(CustomerFactory.build) # explicit local override__set_as_default_factory_for_type__ = TrueCustomerCustomerFactoryUse(CustomerFactory.build)python
import pytest
from polyfactory import Use
from polyfactory.pytest_plugin import register_fixture
@register_fixture
class CustomerFactory(DataclassFactory[Customer]):
__model__ = Customer
__set_as_default_factory_for_type__ = True
@register_fixture
class OrderFactory(DataclassFactory[Order]):
__model__ = Order
customer = Use(CustomerFactory.build) # 显式本地覆盖__set_as_default_factory_for_type__ = TrueCustomerFactoryCustomerUse(CustomerFactory.build)Workflow
工作流程
Step 1: Pick the factory base
步骤1:选择工厂基类
Match the base to your model backend (table above). Wrong base = silent degradation to generic attribute introspection. If your project uses multiple backends (e.g., Pydantic for HTTP DTOs + msgspec for internal events), import each base separately and don't try to share a factory across backends.
根据模型后端选择对应的基类(见上表)。错误的基类会静默退化为通用属性自省。如果项目使用多个后端(例如,HTTP DTO使用Pydantic + 内部事件使用msgspec),请分别导入每个基类,不要尝试跨后端共享工厂。
Step 2: Define one factory per model
步骤2:为每个模型定义一个工厂
Subclass the appropriate base, set . Keep the factory adjacent to the test files that consume it — typically or . Don't put factories in production code paths.
__model__tests/factories.pytests/<feature>/factories.py继承合适的基类,设置。将工厂放在使用它的测试文件附近——通常是或。不要将工厂放在生产代码路径中。
__model__tests/factories.pytests/<feature>/factories.pyStep 3: Customize only what the test cares about
步骤3:仅自定义测试关心的字段
If a field can take any valid value, leave it for the factory to randomize. Override (literal value or ) only fields the assertion depends on. Tests that pin every field defeat the purpose of using a factory.
Use(...)如果字段可以接受任何有效值,留给工厂随机生成。仅覆盖(字面量值或)断言依赖的字段。固定每个字段的测试违背了使用工厂的初衷。
Use(...)Step 4: Register as a pytest fixture (if used widely)
步骤4:注册为pytest夹具(如果广泛使用)
For factories used in many tests, decorate with and consume via the snake-cased fixture name. For one-off use, call directly inline.
@register_fixtureFactory.build()对于在多个测试中使用的工厂,用装饰,并通过蛇形命名的夹具名称使用。对于一次性使用,直接在代码中调用。
@register_fixtureFactory.build()Step 5: Wire cross-model relationships
步骤5:连接跨模型关系
Set on a base factory and let nested fields be populated automatically, or use for a local relationship override.
__set_as_default_factory_for_type__ = TrueUse(OtherFactory.build)在基础工厂上设置,让嵌套字段自动填充,或使用进行本地关系覆盖。
__set_as_default_factory_for_type__ = TrueUse(OtherFactory.build)Step 6: Pin determinism only when needed
步骤6:仅在需要时固定确定性
Tests that assert on specific generated values need . Tests that assert on shape or invariants (e.g., ) should not — leaving randomization on widens coverage across runs.
</workflow>
<guardrails>__random_seed__total >= 0对特定生成值进行断言的测试需要。对形状或不变量(例如)进行断言的测试则不需要——保持随机化可以在多次运行中扩大覆盖范围。
</workflow>
<guardrails>__random_seed__total >= 0Guardrails
注意事项
- Always set . The factory base reads
__model__to introspect annotations; without it__model__errors at runtime, not at class definition..build() - Don't override fields you're about to assert on with random values. Either pin the value () or assert on shape, not both.
status = "pending" - Don't reuse across factories that share a Faker instance. They will collide and produce unexpected duplicates. Use a different seed per factory or a single shared seeded
__random_seed__.__faker__ - Use the right base for the backend. on a
ModelFactoryfalls back to generic introspection and can produce values that violatemsgspec.Structconstraints. Always useMetafor msgspec.MsgspecFactory - Factories belong under . Importing them from production modules ties test data to runtime code and is a refactor hazard.
tests/ - is a parametrize tool, not a build tool. It returns one instance per Union/Optional branch, not per field — use it via
coverage()to fan out test cases over polymorphic shapes.pytest.mark.parametrize - — same rule as msgspec / dishka. The module that defines the factory + model SHOULD avoid future annotations if the model is runtime-introspected. Test modules that use factories MAY freely use future annotations.
from __future__ import annotations
- 始终设置。工厂基类通过读取
__model__来自省注解;如果没有设置,__model__会在运行时而非类定义时报错。.build() - 不要用随机值覆盖即将断言的字段。要么固定值(),要么断言形状,不要两者都做。
status = "pending" - 不要在共享Faker实例的工厂之间复用。它们会冲突并产生意外的重复值。每个工厂使用不同的种子,或使用单个共享的带种子
__random_seed__。__faker__ - 为后端使用正确的基类。在上使用
msgspec.Struct会退化为通用自省,可能生成违反ModelFactory约束的值。请始终为msgspec使用Meta。MsgspecFactory - 工厂应放在目录下。从生产模块导入工厂会将测试数据与运行时代码绑定,存在重构风险。
tests/ - 是参数化工具,不是构建工具。它会为每个Union/Optional分支返回一个实例,而非每个字段——通过
coverage()使用它,在多态形状上展开测试用例。pytest.mark.parametrize - ——与msgspec / dishka的规则相同。如果模块同时定义了可运行时自省的模型类和工厂,那么该模块应避免使用future annotations。使用工厂的测试模块可以自由使用future annotations。
from __future__ import annotations
Validation Checkpoint
验证检查点
Before delivering polyfactory code, verify:
- Factory base matches the model backend (Pydantic → , dataclass →
ModelFactory, msgspec →DataclassFactory, attrs →MsgspecFactory).AttrsFactory - is set on every factory subclass.
__model__ - Factories live under (or a sibling test-only module), never in production code.
tests/ - Fields overridden in the factory match what the test asserts on; fields the test does not care about are left for randomization.
- If the test asserts on exact values, is set; otherwise it is not.
__random_seed__ - is used for factories shared across more than ~2 test files; one-offs call
@register_fixtureinline..build() - Cross-model relationships use or
__set_as_default_factory_for_type__.Use(OtherFactory.build) - Factory module avoids if and only if it co-defines runtime-introspected model classes.
from __future__ import annotations
在交付polyfactory代码之前,请验证:
- 工厂基类与模型后端匹配(Pydantic → ,dataclass →
ModelFactory,msgspec →DataclassFactory,attrs →MsgspecFactory)。AttrsFactory - 每个工厂子类都设置了。
__model__ - 工厂位于(或同级测试专用模块)下,绝不在生产代码中。
tests/ - 工厂中覆盖的字段与测试断言的内容匹配;测试不关心的字段留给随机生成。
- 如果测试断言精确值,则设置了;否则不设置。
__random_seed__ - 对于在超过约2个测试文件中共享的工厂,使用;一次性使用的工厂直接调用
@register_fixture。.build() - 跨模型关系使用或
__set_as_default_factory_for_type__。Use(OtherFactory.build) - 当且仅当工厂模块同时定义了可运行时自省的模型类时,该模块避免使用。
from __future__ import annotations
Example: Litestar handler test with msgspec DTOs and polyfactory
示例:使用msgspec DTO和polyfactory的Litestar处理器测试
python
undefinedpython
undefinedtests/factories.py
tests/factories.py
from polyfactory.factories.msgspec_factory import MsgspecFactory
from polyfactory.pytest_plugin import register_fixture
from myapp.events import OrderCreatedEvent # msgspec.Struct
@register_fixture
class OrderCreatedEventFactory(MsgspecFactory[OrderCreatedEvent]):
model = OrderCreatedEvent
```pythonfrom polyfactory.factories.msgspec_factory import MsgspecFactory
from polyfactory.pytest_plugin import register_fixture
from myapp.events import OrderCreatedEvent # msgspec.Struct
@register_fixture
class OrderCreatedEventFactory(MsgspecFactory[OrderCreatedEvent]):
model = OrderCreatedEvent
```pythontests/test_orders.py
tests/test_orders.py
from future import annotations # consumer module — fine to use future annotations
from litestar.testing import AsyncTestClient
import pytest
@pytest.mark.anyio
async def test_create_order_emits_event(
client: AsyncTestClient,
order_created_event_factory: OrderCreatedEventFactory,
) -> None:
payload = order_created_event_factory.build()
response = await client.post("/orders", json=payload)
assert response.status_code == 201
assert response.json()["id"] == payload.id
The factory provides a fully-populated, validation-passing `OrderCreatedEvent`; the test focuses on the request/response contract instead of constructing fake data inline.
</example>
---from future import annotations # 消费模块——可以使用future annotations
from litestar.testing import AsyncTestClient
import pytest
@pytest.mark.anyio
async def test_create_order_emits_event(
client: AsyncTestClient,
order_created_event_factory: OrderCreatedEventFactory,
) -> None:
payload = order_created_event_factory.build()
response = await client.post("/orders", json=payload)
assert response.status_code == 201
assert response.json()["id"] == payload.id
工厂提供了一个完全填充且通过验证的`OrderCreatedEvent`;测试专注于请求/响应契约,而非在代码中手动构造假数据。
</example>
---References Index
参考索引
For detailed guides, refer to the following documents in :
references/- Factories — Per-backend factory bases (Pydantic / dataclass / msgspec / attrs / TypedDict / ODM), randomization control (,
__random_seed__,__faker__),__allow_none_optionals__defaults, dynamic factories via__set_as_default_factory_for_type__,Factory.create_factoryfor discriminated unions.coverage() - Pytest integration — , fixture scoping, the
@register_fixturemodule, async fixtures, and the difference between class-decorator and function-decorator forms.polyfactory.pytest_plugin - Litestar patterns — Using factories with /
TestClient, parametrizing handler tests viaAsyncTestClient, integrating withcoverage()fixtures, msgspec DTOs, advanced-alchemy model factories, and SAQ task payload generation.litestar-testing
如需详细指南,请参考中的以下文档:
references/- Factories——各后端工厂基类(Pydantic / dataclass / msgspec / attrs / TypedDict / ODM)、随机化控制(、
__random_seed__、__faker__)、__allow_none_optionals__默认值、通过__set_as_default_factory_for_type__创建动态工厂、用于判别联合的Factory.create_factory。coverage() - Pytest integration——、夹具作用域、
@register_fixture模块、异步夹具,以及类装饰器和函数装饰器形式的区别。polyfactory.pytest_plugin - Litestar patterns——将工厂与/
TestClient配合使用、通过AsyncTestClient参数化处理器测试、与coverage()夹具集成、msgspec DTO、advanced-alchemy模型工厂,以及SAQ任务负载生成。litestar-testing
Official References
官方参考
- https://polyfactory.litestar.dev/
- https://polyfactory.litestar.dev/usage/index.html
- https://polyfactory.litestar.dev/usage/library_factories/index.html
- https://polyfactory.litestar.dev/usage/decorators.html
- https://polyfactory.litestar.dev/usage/fixtures.html
- https://polyfactory.litestar.dev/usage/configuration.html
- https://github.com/litestar-org/polyfactory
- https://polyfactory.litestar.dev/
- https://polyfactory.litestar.dev/usage/index.html
- https://polyfactory.litestar.dev/usage/library_factories/index.html
- https://polyfactory.litestar.dev/usage/decorators.html
- https://polyfactory.litestar.dev/usage/fixtures.html
- https://polyfactory.litestar.dev/usage/configuration.html
- https://github.com/litestar-org/polyfactory
Shared Styleguide Baseline
共享风格指南基准
- General Principles
- Python
- 通用原则
- Python