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 للعمل بشكل جيد مع العديد من ORMs (Django، MongoDB، SQLAlchemy)، ويمكن توسيعه بسهولة ليشمل مكتبات أخرى.
وتشمل ميزاته الرئيسية ما يلي:
باي بي: 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. تتوفر قائمة أكثر تفصيلاً في الوثائق الكاملة.
تعلن المصانع عن مجموعة من السمات المستخدمة لإنشاء مثيل لكائن بايثون. يجب تحديد فئة الكائن في حقل 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 مع أدوات رسم الخرائط الارتباطية للكائنات (ORM) من خلال فئات فرعية معينة 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 ()
يمكنك استخدام فئة المصنع كاختصار لاستراتيجية إنشاء مثيل الافتراضية:
# 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
إصدارات Python النشطة بالإضافة إلى PyPy3.
يمكن أن يكون تصحيح أخطاء Factory_boy معقدًا إلى حدٍ ما بسبب سلاسل المكالمات الطويلة. التسجيل التفصيلي متاح من خلال مسجل factory
.
يتوفر المساعد،factor.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.
ينبغي فتح القضايا من خلال قضايا جيثب؛ كلما أمكن ذلك، يجب تضمين طلب السحب. نرحب بالأسئلة والاقتراحات في القائمة البريدية.
يمكن تثبيت تبعيات التطوير في 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
قابلة للاستيراد، حيث يتم استيرادها من كود الاختبار.