factory-boy
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesefactory_boy
factory_boy
Deep Knowledge: Usewith technology:mcp__documentation__fetch_docsfor comprehensive documentation on all declarations, ORM integrations, and patterns.factory-boy
深度知识:使用并指定技术:mcp__documentation__fetch_docs,获取所有声明、ORM集成及模式的完整文档。factory-boy
Installation
安装
bash
pip install factory_boy fakerbash
pip install factory_boy fakerBasic Factory
基础工厂
python
import factory
from myapp.models import User
class UserFactory(factory.Factory):
class Meta:
model = User
first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
email = factory.LazyAttribute(
lambda o: f"{o.first_name}.{o.last_name}@example.com".lower()
)
username = factory.Sequence(lambda n: f"user{n}")
is_active = True
user = UserFactory() # creates (or builds, see Meta.strategy)
user = UserFactory.build() # in-memory, no DB
users = UserFactory.create_batch(5)
stub = UserFactory.stub() # StubObject, no model.__init__()python
import factory
from myapp.models import User
class UserFactory(factory.Factory):
class Meta:
model = User
first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
email = factory.LazyAttribute(
lambda o: f"{o.first_name}.{o.last_name}@example.com".lower()
)
username = factory.Sequence(lambda n: f"user{n}")
is_active = True
user = UserFactory() # 创建(或构建,参考Meta.strategy)
user = UserFactory.build() # 仅在内存中创建,不写入数据库
users = UserFactory.create_batch(5) # 批量创建5个实例
stub = UserFactory.stub() # 创建StubObject,不调用model.__init__()DjangoModelFactory
DjangoModelFactory
python
from factory.django import DjangoModelFactory
class UserFactory(DjangoModelFactory):
class Meta:
model = "auth.User" # 'app.Model' string OK
django_get_or_create = ("username",) # get-or-create on username
username = factory.Sequence(lambda n: f"user{n}")
email = factory.LazyAttribute(lambda o: f"{o.username}@example.com")
password = factory.django.Password("testpass123") # hashed via make_password
class Params:
staff = factory.Trait(is_staff=True)
admin = factory.Trait(is_staff=True, is_superuser=True)python
from factory.django import DjangoModelFactory
class UserFactory(DjangoModelFactory):
class Meta:
model = "auth.User" # 支持'app.Model'字符串格式
django_get_or_create = ("username",) # 根据username执行get-or-create操作
username = factory.Sequence(lambda n: f"user{n}")
email = factory.LazyAttribute(lambda o: f"{o.username}@example.com")
password = factory.django.Password("testpass123") # 通过make_password进行哈希处理
class Params:
staff = factory.Trait(is_staff=True)
admin = factory.Trait(is_staff=True, is_superuser=True)SQLAlchemyModelFactory
SQLAlchemyModelFactory
python
from sqlalchemy.orm import scoped_session, sessionmaker
from factory.alchemy import SQLAlchemyModelFactory
Session = scoped_session(sessionmaker())
class UserFactory(SQLAlchemyModelFactory):
class Meta:
model = User
sqlalchemy_session = Session
sqlalchemy_session_persistence = "commit" # None | "flush" | "commit"
username = factory.Sequence(lambda n: f"user{n}")
email = factory.LazyAttribute(lambda o: f"{o.username}@example.com")python
from sqlalchemy.orm import scoped_session, sessionmaker
from factory.alchemy import SQLAlchemyModelFactory
Session = scoped_session(sessionmaker())
class UserFactory(SQLAlchemyModelFactory):
class Meta:
model = User
sqlalchemy_session = Session
sqlalchemy_session_persistence = "commit" # 可选值:None | "flush" | "commit"
username = factory.Sequence(lambda n: f"user{n}")
email = factory.LazyAttribute(lambda o: f"{o.username}@example.com")In pytest: inject session
在pytest中:注入session
@pytest.fixture
def user(db_session):
UserFactory._meta.sqlalchemy_session = db_session
return UserFactory()
undefined@pytest.fixture
def user(db_session):
UserFactory._meta.sqlalchemy_session = db_session
return UserFactory()
undefinedAll Key Declarations
所有核心字段声明
python
class ArticleFactory(factory.Factory):
class Meta:
model = Article
# Static value
status = "draft"
# Faker provider
title = factory.Faker("sentence", nb_words=6)
body = factory.Faker("paragraph")
uuid = factory.Faker("uuid4")
# Sequence (unique per factory call)
slug = factory.Sequence(lambda n: f"article-{n}")
# LazyAttribute (computed from other fields)
summary = factory.LazyAttribute(lambda o: o.body[:100])
# LazyFunction (zero-arg callable)
created_at = factory.LazyFunction(datetime.utcnow)
# SubFactory (FK)
author = factory.SubFactory(UserFactory)
# SelfAttribute (access parent or sibling fields)
author_email = factory.SelfAttribute("author.email")
# Iterator (cycles through values)
category = factory.Iterator(["tech", "culture", "science"])
# Dict field
metadata = factory.Dict({"source": "web", "version": factory.Sequence(lambda n: n)})
# Maybe (conditional)
published_at = factory.Maybe(
"is_published",
yes_declaration=factory.LazyFunction(datetime.utcnow),
no_declaration=None,
)
is_published = Truepython
class ArticleFactory(factory.Factory):
class Meta:
model = Article
# 静态值
status = "draft"
# Faker提供器
title = factory.Faker("sentence", nb_words=6)
body = factory.Faker("paragraph")
uuid = factory.Faker("uuid4")
# 序列(每次工厂调用生成唯一值)
slug = factory.Sequence(lambda n: f"article-{n}")
# LazyAttribute(根据其他字段计算)
summary = factory.LazyAttribute(lambda o: o.body[:100])
# LazyFunction(无参数可调用对象)
created_at = factory.LazyFunction(datetime.utcnow)
# SubFactory(外键关联)
author = factory.SubFactory(UserFactory)
# SelfAttribute(访问父级或同级字段)
author_email = factory.SelfAttribute("author.email")
# Iterator(循环取值)
category = factory.Iterator(["tech", "culture", "science"])
# Dict字段
metadata = factory.Dict({"source": "web", "version": factory.Sequence(lambda n: n)})
# Maybe(条件声明)
published_at = factory.Maybe(
"is_published",
yes_declaration=factory.LazyFunction(datetime.utcnow),
no_declaration=None,
)
is_published = TrueSubFactory with Overrides
带覆盖配置的SubFactory
python
undefinedpython
undefinedOverride sub-factory fields via __ separator
通过__分隔符覆盖子工厂字段
post = PostFactory(author__username="alice", author__email="alice@test.com")
post = PostFactory(author__username="alice", author__email="alice@test.com")
Override nested sub-factory
覆盖嵌套子工厂
company = CompanyFactory(owner__address__city="Rome")
undefinedcompany = CompanyFactory(owner__address__city="Rome")
undefinedRelatedFactory (Reverse FK)
RelatedFactory(反向外键)
python
class UserFactory(DjangoModelFactory):
class Meta:
model = User
profile = factory.RelatedFactory(
ProfileFactory,
factory_related_name="user", # Profile.user
bio="Default bio",
)python
class UserFactory(DjangoModelFactory):
class Meta:
model = User
profile = factory.RelatedFactory(
ProfileFactory,
factory_related_name="user", # 对应Profile.user字段
bio="默认简介",
)post_generation (M2M, Side Effects)
post_generation(多对多、副作用处理)
python
class ArticleFactory(DjangoModelFactory):
class Meta:
model = Article
skip_postgeneration_save = True
@factory.post_generation
def tags(self, create, extracted, **kwargs):
if not create or not extracted:
return
self.tags.set(extracted)python
class ArticleFactory(DjangoModelFactory):
class Meta:
model = Article
skip_postgeneration_save = True
@factory.post_generation
def tags(self, create, extracted, **kwargs):
if not create or not extracted:
return
self.tags.set(extracted)Usage
使用示例
article = ArticleFactory(tags=[tag1, tag2])
undefinedarticle = ArticleFactory(tags=[tag1, tag2])
undefinedTraits
Traits(特性)
python
class OrderFactory(factory.Factory):
class Meta:
model = Order
status = "pending"
class Params:
shipped = factory.Trait(
status="shipped",
shipped_at=factory.LazyFunction(datetime.utcnow),
)
paid = factory.Trait(
status="paid",
paid_at=factory.LazyFunction(datetime.utcnow),
)python
class OrderFactory(factory.Factory):
class Meta:
model = Order
status = "pending"
class Params:
shipped = factory.Trait(
status="shipped",
shipped_at=factory.LazyFunction(datetime.utcnow),
)
paid = factory.Trait(
status="paid",
paid_at=factory.LazyFunction(datetime.utcnow),
)Usage
使用示例
pending = OrderFactory()
shipped = OrderFactory(shipped=True)
paid = OrderFactory(paid=True)
undefinedpending = OrderFactory()
shipped = OrderFactory(shipped=True)
paid = OrderFactory(paid=True)
undefinedpytest Integration
pytest集成
python
undefinedpython
undefinedconftest.py
conftest.py
import pytest
from myapp.tests.factories import UserFactory, ArticleFactory
@pytest.fixture
def user(db): # for Django
return UserFactory()
@pytest.fixture
def user(db_session): # for SQLAlchemy
UserFactory._meta.sqlalchemy_session = db_session
return UserFactory()
@pytest.fixture
def articles(db):
return ArticleFactory.create_batch(5)
@pytest.fixture(autouse=True)
def reset_sequences():
UserFactory.reset_sequence(0)
ArticleFactory.reset_sequence(0)
yield
undefinedimport pytest
from myapp.tests.factories import UserFactory, ArticleFactory
@pytest.fixture
def user(db): # Django环境下使用
return UserFactory()
@pytest.fixture
def user(db_session): # SQLAlchemy环境下使用
UserFactory._meta.sqlalchemy_session = db_session
return UserFactory()
@pytest.fixture
def articles(db):
return ArticleFactory.create_batch(5)
@pytest.fixture(autouse=True)
def reset_sequences():
UserFactory.reset_sequence(0)
ArticleFactory.reset_sequence(0)
yield
undefinedAnti-Patterns
反模式
| Anti-Pattern | Solution |
|---|---|
| Override in fixture or use |
SubFactory without | Can cause unique constraint violations |
| Not resetting sequences | Use |
| Creating M2M before object exists | Use |
Official docs: https://factoryboy.readthedocs.io/
| 反模式 | 解决方案 |
|---|---|
每个测试中都写 | 在fixture中覆盖配置,或使用 |
SubFactory未设置 | 可能导致唯一约束冲突 |
| 未重置序列 | 使用 |
| 对象创建前就处理多对多关系 | 使用 |