Factory_boy เป็นการทดแทนฟิกซ์เจอร์โดยอิงจาก Factory_bot ของ Thinkbot
ในฐานะเครื่องมือทดแทนฟิกซ์เจอร์ มีจุดมุ่งหมายเพื่อแทนที่ฟิกซ์เจอร์แบบคงที่และบำรุงรักษายากด้วยโรงงานที่ใช้งานง่ายสำหรับวัตถุที่ซับซ้อน
แทนที่จะสร้างการตั้งค่าการทดสอบอย่างละเอียดด้วยการผสมผสานเคสมุมที่เป็นไปได้ทั้งหมด 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 คลาสของวัตถุจะต้องถูกกำหนดในฟิลด์ model
ของ class Meta:
คุณลักษณะ:
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
การรวม Factory_boy กับเครื่องมือ Object Relational Mapping (ORM) มีให้ผ่าน factory.Factory
เฉพาะ คลาสย่อยของโรงงาน:
factory.django.DjangoModelFactory
factory.mogo.MogoFactory
factory.mongoengine.MongoEngineFactory
mongoengine MongoEngineFactoryfactory.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
คุณสามารถเพิ่มแอตทริบิวต์โรงงานส่วนใหญ่ได้โดยใช้ค่าคงที่ที่ได้รับการประเมินเมื่อมีการกำหนดโรงงาน แต่แอตทริบิวต์บางอย่าง (เช่น ฟิลด์ที่มีค่าที่คำนวณจากองค์ประกอบอื่นๆ) จะต้องกำหนดค่าทุกครั้งที่สร้างอินสแตนซ์
คุณสามารถเพิ่มแอตทริบิวต์ "lazy" เหล่านี้ได้ดังนี้:
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
รองรับเวอร์ชัน Python ที่ใช้งานอยู่เช่นเดียวกับ PyPy3
การดีบัก 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
target:
# 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
สามารถนำเข้าได้ เนื่องจากนำเข้าจากโค้ดทดสอบ