基于thoughtbot的factory_bot的Ruby的灵活的测试固定替代品。
项目描述
factory_boy是基于thoughtbot的factory_bot的固定替代品。
作为一个固定替代工具,它旨在用易于使用的工厂替换静态、难以维护的固定值。
而不是构建一个包含所有可能角落案例组合的详尽的测试设置,factory_boy允许你使用针对当前测试定制的对象,同时只声明测试特定的字段
class FooTests(unittest.TestCase):
def test_with_factory_boy(self):
# We need a 200€, paid order, shipping to australia, for a VIP customer
order = OrderFactory(
amount=200,
status='PAID',
customer__is_vip=True,
address__country='AU',
)
# Run the tests here
def test_without_factory_boy(self):
address = Address(
street="42 fubar street",
zipcode="42Z42",
city="Sydney",
country="AU",
)
customer = Customer(
first_name="John",
last_name="Doe",
phone="+1234",
email="john.doe@example.org",
active=True,
is_vip=True,
address=address,
)
# etc.
factory_boy旨在与各种对象关系映射(ORM)工具(Django、MongoDB、SQLAlchemy)良好配合,并且可以轻松扩展到其他库。
其主要功能包括
简洁的声明性语法
在保留全局上下文的同时链式调用工厂方法
支持多种构建策略(已保存/未保存的实例、模拟对象)
支持每个类多个工厂,包括继承
链接
下载
PyPI:https://pypi.ac.cn/project/factory-boy/
$ pip install factory_boy
源代码:https://github.com/FactoryBoy/factory_boy/
$ git clone git://github.com/FactoryBoy/factory_boy/
$ python setup.py install
用法
定义工厂
工厂声明一组用于实例化Python对象的属性。对象的类必须在类Meta属性中的model字段中定义
import factory
from . import models
class UserFactory(factory.Factory):
class Meta:
model = models.User
first_name = 'John'
last_name = 'Doe'
admin = False
# Another, different, factory for the same object
class AdminFactory(factory.Factory):
class Meta:
model = models.User
first_name = 'Admin'
last_name = 'User'
admin = True
ORM集成
factory_boy通过特定的factory.Factory子类与对象关系映射(ORM)工具集成
Django,使用factory.django.DjangoModelFactory
Mogo,使用factory.mogo.MogoFactory
MongoEngine,使用factory.mongoengine.MongoEngineFactory
SQLAlchemy,使用factory.alchemy.SQLAlchemyModelFactory
更多详细信息请参阅ORM部分。
使用工厂
factory_boy支持多种不同的实例化策略:build、create和stub
# Returns a User instance that's not saved
user = UserFactory.build()
# Returns a saved User instance.
# UserFactory must subclass an ORM base class, such as DjangoModelFactory.
user = UserFactory.create()
# Returns a stub object (just a bunch of attributes)
obj = UserFactory.stub()
您可以使用Factory类作为默认实例化策略的快捷方式
# Same as UserFactory.create()
user = UserFactory()
无论使用哪种策略,都可以通过传递关键字参数来覆盖定义的属性
# Build a User instance and override first_name
>>> user = UserFactory.build(first_name='Joe')
>>> user.first_name
"Joe"
还可以在一次调用中创建多个对象
>>> users = UserFactory.build_batch(10, first_name="Joe")
>>> len(users)
10
>>> [user.first_name for user in users]
["Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe"]
真实、随机的值
演示使用随机但真实的值看起来更好;这些真实值还可以帮助发现错误。为此,factory_boy依赖于出色的faker库
class RandomUserFactory(factory.Factory):
class Meta:
model = models.User
first_name = factory.Faker('first_name')
last_name = factory.Faker('last_name')
>>> RandomUserFactory()
<User: Lucy Murray>
可重现的随机值
在测试中使用完全随机数据很快就会成为重现损坏构建的问题。为此,factory_boy提供了位于factory.random模块中的助手来处理它使用的随机种子
import factory.random
def setup_test_environment():
factory.random.reseed_random('my_awesome_project')
# Other setup here
延迟属性
大多数工厂属性可以使用在工厂定义时评估的静态值添加,但某些属性(如值由其他元素计算的字段)将需要每次生成实例时分配值。
这些“延迟”属性可以按如下方式添加
class UserFactory(factory.Factory):
class Meta:
model = models.User
first_name = 'Joe'
last_name = 'Blow'
email = factory.LazyAttribute(lambda a: '{}.{}@example.com'.format(a.first_name, a.last_name).lower())
date_joined = factory.LazyFunction(datetime.now)
>>> UserFactory().email
"joe.blow@example.com"
序列
可以使用序列生成特定格式的唯一值(例如,电子邮件地址)。序列通过使用Sequence或装饰器sequence定义。
class UserFactory(factory.Factory):
class Meta:
model = models.User
email = factory.Sequence(lambda n: 'person{}@example.com'.format(n))
>>> UserFactory().email
'person0@example.com'
>>> UserFactory().email
'person1@example.com'
关联
一些对象具有复杂的字段,这些字段本身应从专门的工厂中定义。这是通过SubFactory助手处理的。
class PostFactory(factory.Factory):
class Meta:
model = models.Post
author = factory.SubFactory(UserFactory)
将使用关联对象的策略
# Builds and saves a User and a Post
>>> post = PostFactory()
>>> post.id is None # Post has been 'saved'
False
>>> post.author.id is None # post.author has been saved
False
# Builds but does not save a User, and then builds but does not save a Post
>>> post = PostFactory.build()
>>> post.id is None
True
>>> post.author.id is None
True
支持策略
factory_boy支持活动的Python版本以及PyPy3。
Python的支持版本。
Django的支持版本。
SQLAlchemy:PyPI上的最新版本https://pypi.ac.cn/project/SQLAlchemy/。
MongoEngine: PyPI上的最新版本.
调试factory_boy
由于调用链较长,调试factory_boy可能相当复杂。可以通过factory日志器获取详细日志。
有一个辅助函数factory.debug(),可以帮助简化调试。
with factory.debug():
obj = TestModel2Factory()
import logging
logger = logging.getLogger('factory')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)
这将产生类似于以下(人工缩进)的消息
BaseFactory: Preparing tests.test_using.TestModel2Factory(extra={})
LazyStub: Computing values for tests.test_using.TestModel2Factory(two=<OrderedDeclarationWrapper for <factory.declarations.SubFactory object at 0x1e15610>>)
SubFactory: Instantiating tests.test_using.TestModelFactory(__containers=(<LazyStub for tests.test_using.TestModel2Factory>,), one=4), create=True
BaseFactory: Preparing tests.test_using.TestModelFactory(extra={'__containers': (<LazyStub for tests.test_using.TestModel2Factory>,), 'one': 4})
LazyStub: Computing values for tests.test_using.TestModelFactory(one=4)
LazyStub: Computed values, got tests.test_using.TestModelFactory(one=4)
BaseFactory: Generating tests.test_using.TestModelFactory(one=4)
LazyStub: Computed values, got tests.test_using.TestModel2Factory(two=<tests.test_using.TestModel object at 0x1e15410>)
BaseFactory: Generating tests.test_using.TestModel2Factory(two=<tests.test_using.TestModel object at 0x1e15410>)
贡献
factory_boy采用MIT许可证。
应在GitHub Issues中打开问题;尽可能提供pull request。欢迎在邮件列表上提问和建议。
开发依赖项可以安装在一个虚拟环境中
$ pip install --editable '.[dev]'
所有pull request都应该通过测试套件,只需简单地运行
$ make testall
为了测试覆盖率,请使用
$ make coverage
要使用特定框架版本进行测试,可以使用tox目标
# list all tox environments
$ tox --listenvs
# run tests inside a specific environment (django/mongoengine/SQLAlchemy are not installed)
$ tox -e py310
# run tests inside a specific environment (django)
$ tox -e py310-djangomain
# run tests inside a specific environment (alchemy)
$ tox -e py310-alchemy
# run tests inside a specific environment (mongoengine)
$ tox -e py310-mongo
打包
对于有兴趣将FactoryBoy打包到下游分发渠道(例如.deb、.rpm、.ebuild)的用户,以下提示可能有所帮助
依赖关系
该软件包的运行时依赖关系列在setup.cfg中。构建和测试库有用的依赖关系由dev和doc extras覆盖。
此外,所有开发/测试任务都通过make(1)驱动。
构建
要运行构建步骤(目前仅用于文档),运行
python setup.py egg_info
make doc
测试
在测试活动Python环境时,运行以下命令
make test
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分发
构建分发
factory_boy-3.3.1.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 8317aa5289cdfc45f9cae570feb07a6177316c82e34d14df3c2e1f22f26abef0 |
|
MD5 | f3ea85ca5ad5b3c906b87d82ae53db67 |
|
BLAKE2b-256 | 993d8070dde623341401b1c80156583d4c793058fe250450178218bb6e45526c |
factory_boy-3.3.1-py2.py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 7b1113c49736e1e9995bc2a18f4dbf2c52cf0f841103517010b1d825712ce3ca |
|
MD5 | adfc9787544914bd242296df7b449619 |
|
BLAKE2b-256 | 33cf44ec67152f3129d0114c1499dd34f0a0a0faf43d9c2af05bc535746ca482 |