Factory_boy는 Thinkbot의 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 = "[email protected]" ,
active = True ,
is_vip = True ,
address = address ,
)
# etc.
Factory_boy는 다양한 ORM(Django, MongoDB, SQLAlchemy)과 잘 작동하도록 설계되었으며 다른 라이브러리에서도 쉽게 확장할 수 있습니다.
주요 기능은 다음과 같습니다:
PyPI: https://pypi.org/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
메모
이 섹션에서는 Factory_boy 기능에 대한 간략한 요약을 제공합니다. 더 자세한 목록은 전체 문서에서 확인할 수 있습니다.
팩토리는 Python 객체를 인스턴스화하는 데 사용되는 속성 집합을 선언합니다. 객체의 클래스는 class 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
하위 클래스를 통해 제공됩니다.
factory.django.DjangoModelFactory
포함)factory.mogo.MogoFactory
포함factory.mongoengine.MongoEngineFactory
포함)factory.alchemy.SQLAlchemyModelFactory
포함)자세한 내용은 ORM 섹션에서 확인할 수 있습니다.
Factory_boy는 빌드, 생성, 스텁 등 다양한 인스턴스화 전략을 지원합니다.
# 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
"[email protected]"
메모
LazyAttribute
LazyFunction
이 인수를 보내지 않을 때 생성되는 개체를 인수로 사용하여 함수를 호출합니다.
시퀀스를 사용하여 특정 형식(예: 이메일 주소)의 고유 값을 생성할 수 있습니다. 시퀀스는 Sequence
또는 데코레이터 sequence
사용하여 정의됩니다.
class UserFactory ( factory . Factory ):
class Meta :
model = models . User
email = factory . Sequence ( lambda n : 'person{}@example.com' . format ( n ))
> >> UserFactory (). email
'[email protected]'
> >> UserFactory (). email
'[email protected]'
일부 객체에는 전용 팩토리에서 정의해야 하는 복잡한 필드가 있습니다. 이는 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
PyPy3뿐만 아니라 활성 Python 버전도 지원합니다.
긴 호출 체인으로 인해 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 이슈를 통해 열려야 합니다. 가능할 때마다 끌어오기 요청을 포함해야 합니다. 질문과 제안은 메일링 리스트를 통해 환영합니다.
개발 종속성은 다음을 사용하여 virtualenv에 설치할 수 있습니다.
$ pip install --editable ' .[dev] '
모든 끌어오기 요청은 테스트 모음을 통과해야 하며 다음과 같이 간단하게 시작할 수 있습니다.
$ 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
추가 항목에서 다룹니다.
게다가 모든 개발/테스트 작업은 make(1)
통해 이루어집니다.
빌드 단계를 실행하려면(현재는 문서에만 해당) 다음을 실행하세요.
python setup.py egg_info
make doc
활성 Python 환경을 테스트할 때 다음을 실행합니다.
make test
메모
factory
모듈은 테스트 코드에서 가져오므로 가져올 수 있는지 확인해야 합니다.