diff options
author | Carl Meyer <carl@oddbird.net> | 2012-01-12 08:48:34 -0700 |
---|---|---|
committer | Carl Meyer <carl@oddbird.net> | 2012-01-12 08:48:34 -0700 |
commit | 24b6a6b83cfb7cd5bab304bb8cc22383cf461d85 (patch) | |
tree | 3b3939aa09d32089fd8077c8eece8193642b262d | |
parent | 86393d4d1117426bc2aafbfb9f11f96c463f05f1 (diff) | |
parent | 363fa7b470286f2b38ab33a7e986bfd000f25d86 (diff) | |
download | factory-boy-24b6a6b83cfb7cd5bab304bb8cc22383cf461d85.tar factory-boy-24b6a6b83cfb7cd5bab304bb8cc22383cf461d85.tar.gz |
Merge branch 'master' into allow-public-classmethods
-rw-r--r-- | README.rst | 4 | ||||
-rw-r--r-- | factory/__init__.py | 3 | ||||
-rw-r--r-- | factory/containers.py | 30 | ||||
-rw-r--r-- | factory/declarations.py | 49 | ||||
-rw-r--r-- | tests/__init__.py | 1 | ||||
-rw-r--r-- | tests/test_base.py | 364 | ||||
-rw-r--r-- | tests/test_containers.py | 27 | ||||
-rw-r--r-- | tests/test_using.py | 477 |
8 files changed, 574 insertions, 381 deletions
@@ -19,9 +19,9 @@ Download Github: http://github.com/rbarrois/factory_boy/ -easy_install:: +PyPI:: - easy_install factory_boy + pip install factory_boy Source:: diff --git a/factory/__init__.py b/factory/__init__.py index b673162..7f40d6f 100644 --- a/factory/__init__.py +++ b/factory/__init__.py @@ -46,10 +46,13 @@ from declarations import ( LazyAttribute, Sequence, LazyAttributeSequence, + SelfAttribute, + LazyContainerAttribute, SubFactory, lazy_attribute, sequence, lazy_attribute_sequence, + lazy_container_attribute, ) diff --git a/factory/containers.py b/factory/containers.py index 9fe8e46..0218e47 100644 --- a/factory/containers.py +++ b/factory/containers.py @@ -49,10 +49,11 @@ class LazyStub(object): __initialized = False - def __init__(self, attrs): + def __init__(self, attrs, containers=()): self.__attrs = attrs self.__values = {} self.__pending = [] + self.__containers = containers self.__initialized = True def __fill__(self): @@ -82,7 +83,7 @@ class LazyStub(object): val = self.__attrs[name] if isinstance(val, LazyValue): self.__pending.append(name) - val = val.evaluate(self) + val = val.evaluate(self, self.__containers) assert name == self.__pending.pop() self.__values[name] = val return val @@ -135,7 +136,7 @@ class DeclarationDict(dict): class LazyValue(object): """Some kind of "lazy evaluating" object.""" - def evaluate(self, obj): + def evaluate(self, obj, containers=()): """Compute the value, using the given object.""" raise NotImplementedError("This is an abstract method.") @@ -156,8 +157,12 @@ class SubFactoryWrapper(LazyValue): self.subfields = subfields self.create = create - def evaluate(self, obj): - return self.subfactory.evaluate(self.create, self.subfields) + def evaluate(self, obj, containers=()): + expanded_containers = (obj,) + if containers: + expanded_containers += tuple(containers) + return self.subfactory.evaluate(self.create, self.subfields, + expanded_containers) class OrderedDeclarationWrapper(LazyValue): @@ -175,8 +180,15 @@ class OrderedDeclarationWrapper(LazyValue): self.declaration = declaration self.sequence = sequence - def evaluate(self, obj): - return self.declaration.evaluate(self.sequence, obj) + def evaluate(self, obj, containers=()): + """Lazily evaluate the attached OrderedDeclaration. + + Args: + obj (LazyStub): the object being built + containers (object list): the chain of containers of the object + being built, its immediate holder being first. + """ + return self.declaration.evaluate(self.sequence, obj, containers) class AttributeBuilder(object): @@ -195,7 +207,9 @@ class AttributeBuilder(object): if not extra: extra = {} + self.factory = factory + self._containers = extra.pop('__containers', None) self._attrs = factory.declarations(extra) self._subfields = self._extract_subfields() @@ -229,7 +243,7 @@ class AttributeBuilder(object): v = OrderedDeclarationWrapper(v, self.factory.sequence) wrapped_attrs[k] = v - return LazyStub(wrapped_attrs).__fill__() + return LazyStub(wrapped_attrs, containers=self._containers).__fill__() class StubObject(object): diff --git a/factory/declarations.py b/factory/declarations.py index 4a5bf97..c28e6af 100644 --- a/factory/declarations.py +++ b/factory/declarations.py @@ -28,7 +28,7 @@ class OrderedDeclaration(object): in the same factory. """ - def evaluate(self, sequence, obj): + def evaluate(self, sequence, obj, containers=()): """Evaluate this declaration. Args: @@ -36,6 +36,8 @@ class OrderedDeclaration(object): the current instance obj (containers.LazyStub): The object holding currently computed attributes + containers (list of containers.LazyStub): The chain of SubFactory + which led to building this object. """ raise NotImplementedError('This is an abstract method') @@ -52,7 +54,7 @@ class LazyAttribute(OrderedDeclaration): super(LazyAttribute, self).__init__(*args, **kwargs) self.function = function - def evaluate(self, sequence, obj): + def evaluate(self, sequence, obj, containers=()): return self.function(obj) @@ -67,7 +69,7 @@ class SelfAttribute(OrderedDeclaration): super(SelfAttribute, self).__init__(*args, **kwargs) self.attribute_name = attribute_name - def evaluate(self, sequence, obj): + def evaluate(self, sequence, obj, containers=()): # TODO(rbarrois): allow the use of ATTR_SPLITTER to fetch fields of # subfactories. return getattr(obj, self.attribute_name) @@ -89,7 +91,7 @@ class Sequence(OrderedDeclaration): self.function = function self.type = type - def evaluate(self, sequence, obj): + def evaluate(self, sequence, obj, containers=()): return self.function(self.type(sequence)) @@ -102,10 +104,41 @@ class LazyAttributeSequence(Sequence): type (function): A function converting an integer into the expected kind of counter for the 'function' attribute. """ - def evaluate(self, sequence, obj): + def evaluate(self, sequence, obj, containers=()): return self.function(obj, self.type(sequence)) +class LazyContainerAttribute(OrderedDeclaration): + """Variant of LazyAttribute, also receives the containers of the object. + + Attributes: + function (function): A function, expecting the current LazyStub and the + (optional) object having a subfactory containing this attribute. + strict (bool): Whether evaluating should fail when the containers are + not passed in (i.e used outside a SubFactory). + """ + def __init__(self, function, strict=True, *args, **kwargs): + super(LazyContainerAttribute, self).__init__(*args, **kwargs) + self.function = function + self.strict = strict + + def evaluate(self, sequence, obj, containers=()): + """Evaluate the current LazyContainerAttribute. + + Args: + obj (LazyStub): a lazy stub of the object being constructed, if + needed. + containers (LazyStub): a lazy stub of a factory being evaluated, with + a SubFactory building 'obj'. + """ + if self.strict and not containers: + raise TypeError( + "A LazyContainerAttribute in 'strict' mode can only be used " + "within a SubFactory.") + + return self.function(obj, containers) + + class SubFactory(OrderedDeclaration): """Base class for attributes based upon a sub-factory. @@ -120,7 +153,7 @@ class SubFactory(OrderedDeclaration): self.defaults = kwargs self.factory = factory - def evaluate(self, create, extra): + def evaluate(self, create, extra, containers): """Evaluate the current definition and fill its attributes. Uses attributes definition in the following order: @@ -132,6 +165,7 @@ class SubFactory(OrderedDeclaration): defaults = dict(self.defaults) if extra: defaults.update(extra) + defaults['__containers'] = containers attrs = self.factory.attributes(create, defaults) @@ -151,3 +185,6 @@ def sequence(func): def lazy_attribute_sequence(func): return LazyAttributeSequence(func) + +def lazy_container_attribute(func): + return LazyContainerAttribute(func, strict=False) diff --git a/tests/__init__.py b/tests/__init__.py index 14f1e9d..7ab3567 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -4,3 +4,4 @@ from .test_base import * from .test_containers import * from .test_declarations import * +from .test_using import * diff --git a/tests/test_base.py b/tests/test_base.py index aaaa65f..97749f6 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -55,211 +55,13 @@ class SafetyTestCase(unittest.TestCase): self.assertRaises(RuntimeError, base.BaseFactory) -class SimpleBuildTestCase(unittest.TestCase): - """Tests the minimalist 'factory.build/create' functions.""" - - def test_build(self): - obj = base.build(TestObject, two=2) - self.assertEqual(obj.one, None) - self.assertEqual(obj.two, 2) - self.assertEqual(obj.three, None) - self.assertEqual(obj.four, None) - - def test_complex(self): - obj = base.build(TestObject, two=2, three=declarations.LazyAttribute(lambda o: o.two + 1)) - self.assertEqual(obj.one, None) - self.assertEqual(obj.two, 2) - self.assertEqual(obj.three, 3) - self.assertEqual(obj.four, None) - - def test_create(self): - obj = base.create(FakeDjangoModel, foo='bar') - self.assertEqual(obj.id, 1) - self.assertEqual(obj.foo, 'bar') - - def test_stub(self): - obj = base.stub(TestObject, three=3) - self.assertEqual(obj.three, 3) - self.assertFalse(hasattr(obj, 'two')) - - def test_make_factory(self): - fact = base.make_factory(TestObject, two=2, three=declarations.LazyAttribute(lambda o: o.two + 1)) - - obj = fact.build() - self.assertEqual(obj.one, None) - self.assertEqual(obj.two, 2) - self.assertEqual(obj.three, 3) - self.assertEqual(obj.four, None) - - obj = fact.build(two=4) - self.assertEqual(obj.one, None) - self.assertEqual(obj.two, 4) - self.assertEqual(obj.three, 5) - self.assertEqual(obj.four, None) - - class FactoryTestCase(unittest.TestCase): - def testAttribute(self): - class TestObjectFactory(base.Factory): - one = 'one' - - test_object = TestObjectFactory.build() - self.assertEqual(test_object.one, 'one') - - def testSequence(self): - class TestObjectFactory(base.Factory): - one = declarations.Sequence(lambda n: 'one' + n) - two = declarations.Sequence(lambda n: 'two' + n) - - test_object0 = TestObjectFactory.build() - self.assertEqual(test_object0.one, 'one0') - self.assertEqual(test_object0.two, 'two0') - - test_object1 = TestObjectFactory.build() - self.assertEqual(test_object1.one, 'one1') - self.assertEqual(test_object1.two, 'two1') - - def testSequenceCustomBegin(self): - class TestObjectFactory(base.Factory): - @classmethod - def _setup_next_sequence(cls): - return 42 - - one = declarations.Sequence(lambda n: 'one' + n) - two = declarations.Sequence(lambda n: 'two' + n) - - test_object0 = TestObjectFactory.build() - self.assertEqual('one42', test_object0.one) - self.assertEqual('two42', test_object0.two) - - test_object1 = TestObjectFactory.build() - self.assertEqual('one43', test_object1.one) - self.assertEqual('two43', test_object1.two) - - def testLazyAttribute(self): - class TestObjectFactory(base.Factory): - one = declarations.LazyAttribute(lambda a: 'abc' ) - two = declarations.LazyAttribute(lambda a: a.one + ' xyz') - - test_object = TestObjectFactory.build() - self.assertEqual(test_object.one, 'abc') - self.assertEqual(test_object.two, 'abc xyz') - def testLazyAttributeNonExistentParam(self): class TestObjectFactory(base.Factory): one = declarations.LazyAttribute(lambda a: a.does_not_exist ) self.assertRaises(AttributeError, TestObjectFactory) - def testLazyAttributeSequence(self): - class TestObjectFactory(base.Factory): - one = declarations.LazyAttributeSequence(lambda a, n: 'abc' + n) - two = declarations.LazyAttributeSequence(lambda a, n: a.one + ' xyz' + n) - - test_object0 = TestObjectFactory.build() - self.assertEqual(test_object0.one, 'abc0') - self.assertEqual(test_object0.two, 'abc0 xyz0') - - test_object1 = TestObjectFactory.build() - self.assertEqual(test_object1.one, 'abc1') - self.assertEqual(test_object1.two, 'abc1 xyz1') - - def testLazyAttributeDecorator(self): - class TestObjectFactory(base.Factory): - @declarations.lazy_attribute - def one(a): - return 'one' - - test_object = TestObjectFactory.build() - self.assertEqual(test_object.one, 'one') - - def testSelfAttribute(self): - class TestObjectFactory(base.Factory): - one = 'xx' - two = declarations.SelfAttribute('one') - - test_object = TestObjectFactory.build(one=1) - self.assertEqual(1, test_object.two) - - def testSequenceDecorator(self): - class TestObjectFactory(base.Factory): - @declarations.sequence - def one(n): - return 'one' + n - - test_object = TestObjectFactory.build() - self.assertEqual(test_object.one, 'one0') - - def testLazyAttributeSequenceDecorator(self): - class TestObjectFactory(base.Factory): - @declarations.lazy_attribute_sequence - def one(a, n): - return 'one' + n - @declarations.lazy_attribute_sequence - def two(a, n): - return a.one + ' two' + n - - test_object = TestObjectFactory.build() - self.assertEqual(test_object.one, 'one0') - self.assertEqual(test_object.two, 'one0 two0') - - def testBuildWithParameters(self): - class TestObjectFactory(base.Factory): - one = declarations.Sequence(lambda n: 'one' + n) - two = declarations.Sequence(lambda n: 'two' + n) - - test_object0 = TestObjectFactory.build(three='three') - self.assertEqual(test_object0.one, 'one0') - self.assertEqual(test_object0.two, 'two0') - self.assertEqual(test_object0.three, 'three') - - test_object1 = TestObjectFactory.build(one='other') - self.assertEqual(test_object1.one, 'other') - self.assertEqual(test_object1.two, 'two1') - - def testCreate(self): - class TestModelFactory(base.Factory): - one = 'one' - - test_model = TestModelFactory.create() - self.assertEqual(test_model.one, 'one') - self.assertTrue(test_model.id) - - def testInheritance(self): - class TestObjectFactory(base.Factory): - one = 'one' - two = declarations.LazyAttribute(lambda a: a.one + ' two') - - class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject - - three = 'three' - four = declarations.LazyAttribute(lambda a: a.three + ' four') - - test_object = TestObjectFactory2.build() - self.assertEqual(test_object.one, 'one') - self.assertEqual(test_object.two, 'one two') - self.assertEqual(test_object.three, 'three') - self.assertEqual(test_object.four, 'three four') - - test_object_alt = TestObjectFactory.build() - self.assertEqual(None, test_object_alt.three) - - def testInheritanceWithInheritedClass(self): - class TestObjectFactory(base.Factory): - one = 'one' - two = declarations.LazyAttribute(lambda a: a.one + ' two') - - class TestFactory(TestObjectFactory): - three = 'three' - four = declarations.LazyAttribute(lambda a: a.three + ' four') - - test_object = TestFactory.build() - self.assertEqual(test_object.one, 'one') - self.assertEqual(test_object.two, 'one two') - self.assertEqual(test_object.three, 'three') - self.assertEqual(test_object.four, 'three four') - def testInheritanceWithSequence(self): """Tests that sequence IDs are shared between parent and son.""" class TestObjectFactory(base.Factory): @@ -275,36 +77,6 @@ class FactoryTestCase(unittest.TestCase): ones = set([x.one for x in (parent, alt_parent, sub, alt_sub)]) self.assertEqual(4, len(ones)) - def testDualInheritance(self): - class TestObjectFactory(base.Factory): - one = 'one' - - class TestOtherFactory(base.Factory): - FACTORY_FOR = TestObject - two = 'two' - four = 'four' - - class TestFactory(TestObjectFactory, TestOtherFactory): - three = 'three' - - obj = TestFactory.build(two=2) - self.assertEqual('one', obj.one) - self.assertEqual(2, obj.two) - self.assertEqual('three', obj.three) - self.assertEqual('four', obj.four) - - def testSetCreationFunction(self): - def creation_function(class_to_create, **kwargs): - return "This doesn't even return an instance of {0}".format(class_to_create.__name__) - - class TestModelFactory(base.Factory): - pass - - TestModelFactory.set_creation_function(creation_function) - - test_object = TestModelFactory.create() - self.assertEqual(test_object, "This doesn't even return an instance of TestModel") - class FactoryDefaultStrategyTestCase(unittest.TestCase): def setUp(self): self.default_strategy = base.Factory.default_strategy @@ -332,142 +104,6 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): self.assertEqual(test_model.one, 'one') self.assertTrue(test_model.id) - def testSubFactory(self): - class TestModel2(FakeDjangoModel): - pass - - class TestModelFactory(base.Factory): - FACTORY_FOR = TestModel - one = 3 - - class TestModel2Factory(base.Factory): - FACTORY_FOR = TestModel2 - two = declarations.SubFactory(TestModelFactory, one=1) - - test_model = TestModel2Factory(two__one=4) - self.assertEqual(4, test_model.two.one) - self.assertEqual(1, test_model.id) - self.assertEqual(1, test_model.two.id) - - def testSubFactoryWithLazyFields(self): - class TestModel2(FakeDjangoModel): - pass - - class TestModelFactory(base.Factory): - FACTORY_FOR = TestModel - - class TestModel2Factory(base.Factory): - FACTORY_FOR = TestModel2 - two = declarations.SubFactory(TestModelFactory, - one=declarations.Sequence(lambda n: 'x%sx' % n), - two=declarations.LazyAttribute( - lambda o: '%s%s' % (o.one, o.one))) - - test_model = TestModel2Factory(one=42) - self.assertEqual('x0x', test_model.two.one) - self.assertEqual('x0xx0x', test_model.two.two) - - def testSubFactoryOverriding(self): - class TestObject(object): - def __init__(self, **kwargs): - for k, v in kwargs.iteritems(): - setattr(self, k, v) - - class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - - class WrappingTestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - - wrapped = declarations.SubFactory(TestObjectFactory, two=2, four=4) - wrapped__two = 4 - wrapped__three = 3 - - wrapping = WrappingTestObjectFactory.build() - self.assertEqual(wrapping.wrapped.two, 4) - self.assertEqual(wrapping.wrapped.three, 3) - self.assertEqual(wrapping.wrapped.four, 4) - - - def testNestedSubFactory(self): - """Test nested sub-factories.""" - - class TestObject(object): - def __init__(self, **kwargs): - for k, v in kwargs.iteritems(): - setattr(self, k, v) - - class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - - class WrappingTestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - - wrapped = declarations.SubFactory(TestObjectFactory) - wrapped_bis = declarations.SubFactory(TestObjectFactory, one=1) - - class OuterWrappingTestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - - wrap = declarations.SubFactory(WrappingTestObjectFactory, wrapped__two=2) - - outer = OuterWrappingTestObjectFactory.build() - self.assertEqual(outer.wrap.wrapped.two, 2) - self.assertEqual(outer.wrap.wrapped_bis.one, 1) - - def testNestedSubFactoryWithOverriddenSubFactories(self): - """Test nested sub-factories, with attributes overridden with subfactories.""" - - class TestObject(object): - def __init__(self, **kwargs): - for k, v in kwargs.iteritems(): - setattr(self, k, v) - - class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - two = 'two' - - class WrappingTestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - - wrapped = declarations.SubFactory(TestObjectFactory) - friend = declarations.LazyAttribute(lambda o: o.wrapped.two.four + 1) - - class OuterWrappingTestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - - wrap = declarations.SubFactory(WrappingTestObjectFactory, - wrapped__two=declarations.SubFactory(TestObjectFactory, four=4)) - - outer = OuterWrappingTestObjectFactory.build() - self.assertEqual(outer.wrap.wrapped.two.four, 4) - self.assertEqual(outer.wrap.friend, 5) - - def testSubFactoryAndInheritance(self): - """Test inheriting from a factory with subfactories, overriding.""" - class TestObject(object): - def __init__(self, **kwargs): - for k, v in kwargs.iteritems(): - setattr(self, k, v) - - class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - two = 'two' - - class WrappingTestObjectFactory(base.Factory): - FACTORY_FOR = TestObject - - wrapped = declarations.SubFactory(TestObjectFactory) - friend = declarations.LazyAttribute(lambda o: o.wrapped.two + 1) - - class ExtendedWrappingTestObjectFactory(WrappingTestObjectFactory): - wrapped__two = 4 - - wrapping = ExtendedWrappingTestObjectFactory.build() - self.assertEqual(wrapping.wrapped.two, 4) - self.assertEqual(wrapping.friend, 5) - - def testStubStrategy(self): base.Factory.default_strategy = base.STUB_STRATEGY diff --git a/tests/test_containers.py b/tests/test_containers.py index b9eaab6..b4c5c52 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -43,12 +43,37 @@ class LazyStubTestCase(unittest.TestCase): self.assertRaises(AttributeError, getattr, stub, 'three') + def test_accessing_container(self): + class LazyAttr(containers.LazyValue): + def __init__(self, obj_attr, container_attr): + self.obj_attr = obj_attr + self.container_attr = container_attr + + def evaluate(self, obj, containers=()): + if containers: + add = getattr(containers[0], self.container_attr) + else: + add = 0 + return getattr(obj, self.obj_attr) + add + + class DummyContainer(object): + three = 3 + + stub = containers.LazyStub({'one': LazyAttr('two', 'three'), 'two': 2, 'three': 42}, + containers=(DummyContainer(),)) + + self.assertEqual(5, stub.one) + + stub = containers.LazyStub({'one': LazyAttr('two', 'three'), 'two': 2, 'three': 42}, + containers=()) + self.assertEqual(2, stub.one) + def test_cyclic_definition(self): class LazyAttr(containers.LazyValue): def __init__(self, attrname): self.attrname = attrname - def evaluate(self, obj): + def evaluate(self, obj, container=None): return 1 + getattr(obj, self.attrname) stub = containers.LazyStub({'one': LazyAttr('two'), 'two': LazyAttr('one')}) diff --git a/tests/test_using.py b/tests/test_using.py new file mode 100644 index 0000000..e0e59cd --- /dev/null +++ b/tests/test_using.py @@ -0,0 +1,477 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2011 Raphaƫl Barrois +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +"""Tests using factory.""" + +import unittest + +import factory + + + +class TestObject(object): + def __init__(self, one=None, two=None, three=None, four=None): + self.one = one + self.two = two + self.three = three + self.four = four + +class FakeDjangoModel(object): + class FakeDjangoManager(object): + def create(self, **kwargs): + fake_model = FakeDjangoModel(**kwargs) + fake_model.id = 1 + return fake_model + + objects = FakeDjangoManager() + + def __init__(self, **kwargs): + for name, value in kwargs.iteritems(): + setattr(self, name, value) + self.id = None + +class TestModel(FakeDjangoModel): + pass + + +class SimpleBuildTestCase(unittest.TestCase): + """Tests the minimalist 'factory.build/create' functions.""" + + def test_build(self): + obj = factory.build(TestObject, two=2) + self.assertEqual(obj.one, None) + self.assertEqual(obj.two, 2) + self.assertEqual(obj.three, None) + self.assertEqual(obj.four, None) + + def test_complex(self): + obj = factory.build(TestObject, two=2, three=factory.LazyAttribute(lambda o: o.two + 1)) + self.assertEqual(obj.one, None) + self.assertEqual(obj.two, 2) + self.assertEqual(obj.three, 3) + self.assertEqual(obj.four, None) + + def test_create(self): + obj = factory.create(FakeDjangoModel, foo='bar') + self.assertEqual(obj.id, 1) + self.assertEqual(obj.foo, 'bar') + + def test_stub(self): + obj = factory.stub(TestObject, three=3) + self.assertEqual(obj.three, 3) + self.assertFalse(hasattr(obj, 'two')) + + def test_make_factory(self): + fact = factory.make_factory(TestObject, two=2, three=factory.LazyAttribute(lambda o: o.two + 1)) + + obj = fact.build() + self.assertEqual(obj.one, None) + self.assertEqual(obj.two, 2) + self.assertEqual(obj.three, 3) + self.assertEqual(obj.four, None) + + obj = fact.build(two=4) + self.assertEqual(obj.one, None) + self.assertEqual(obj.two, 4) + self.assertEqual(obj.three, 5) + self.assertEqual(obj.four, None) + + +class FactoryTestCase(unittest.TestCase): + def testAttribute(self): + class TestObjectFactory(factory.Factory): + one = 'one' + + test_object = TestObjectFactory.build() + self.assertEqual(test_object.one, 'one') + + def testSequence(self): + class TestObjectFactory(factory.Factory): + one = factory.Sequence(lambda n: 'one' + n) + two = factory.Sequence(lambda n: 'two' + n) + + test_object0 = TestObjectFactory.build() + self.assertEqual(test_object0.one, 'one0') + self.assertEqual(test_object0.two, 'two0') + + test_object1 = TestObjectFactory.build() + self.assertEqual(test_object1.one, 'one1') + self.assertEqual(test_object1.two, 'two1') + + def testSequenceCustomBegin(self): + class TestObjectFactory(factory.Factory): + @classmethod + def _setup_next_sequence(cls): + return 42 + + one = factory.Sequence(lambda n: 'one' + n) + two = factory.Sequence(lambda n: 'two' + n) + + test_object0 = TestObjectFactory.build() + self.assertEqual('one42', test_object0.one) + self.assertEqual('two42', test_object0.two) + + test_object1 = TestObjectFactory.build() + self.assertEqual('one43', test_object1.one) + self.assertEqual('two43', test_object1.two) + + def testLazyAttribute(self): + class TestObjectFactory(factory.Factory): + one = factory.LazyAttribute(lambda a: 'abc' ) + two = factory.LazyAttribute(lambda a: a.one + ' xyz') + + test_object = TestObjectFactory.build() + self.assertEqual(test_object.one, 'abc') + self.assertEqual(test_object.two, 'abc xyz') + + def testLazyAttributeSequence(self): + class TestObjectFactory(factory.Factory): + one = factory.LazyAttributeSequence(lambda a, n: 'abc' + n) + two = factory.LazyAttributeSequence(lambda a, n: a.one + ' xyz' + n) + + test_object0 = TestObjectFactory.build() + self.assertEqual(test_object0.one, 'abc0') + self.assertEqual(test_object0.two, 'abc0 xyz0') + + test_object1 = TestObjectFactory.build() + self.assertEqual(test_object1.one, 'abc1') + self.assertEqual(test_object1.two, 'abc1 xyz1') + + def testLazyAttributeDecorator(self): + class TestObjectFactory(factory.Factory): + @factory.lazy_attribute + def one(a): + return 'one' + + test_object = TestObjectFactory.build() + self.assertEqual(test_object.one, 'one') + + def testSelfAttribute(self): + class TestObjectFactory(factory.Factory): + one = 'xx' + two = factory.SelfAttribute('one') + + test_object = TestObjectFactory.build(one=1) + self.assertEqual(1, test_object.two) + + def testSequenceDecorator(self): + class TestObjectFactory(factory.Factory): + @factory.sequence + def one(n): + return 'one' + n + + test_object = TestObjectFactory.build() + self.assertEqual(test_object.one, 'one0') + + def testLazyAttributeSequenceDecorator(self): + class TestObjectFactory(factory.Factory): + @factory.lazy_attribute_sequence + def one(a, n): + return 'one' + n + @factory.lazy_attribute_sequence + def two(a, n): + return a.one + ' two' + n + + test_object = TestObjectFactory.build() + self.assertEqual(test_object.one, 'one0') + self.assertEqual(test_object.two, 'one0 two0') + + def testBuildWithParameters(self): + class TestObjectFactory(factory.Factory): + one = factory.Sequence(lambda n: 'one' + n) + two = factory.Sequence(lambda n: 'two' + n) + + test_object0 = TestObjectFactory.build(three='three') + self.assertEqual(test_object0.one, 'one0') + self.assertEqual(test_object0.two, 'two0') + self.assertEqual(test_object0.three, 'three') + + test_object1 = TestObjectFactory.build(one='other') + self.assertEqual(test_object1.one, 'other') + self.assertEqual(test_object1.two, 'two1') + + def testCreate(self): + class TestModelFactory(factory.Factory): + one = 'one' + + test_model = TestModelFactory.create() + self.assertEqual(test_model.one, 'one') + self.assertTrue(test_model.id) + + def testInheritance(self): + class TestObjectFactory(factory.Factory): + one = 'one' + two = factory.LazyAttribute(lambda a: a.one + ' two') + + class TestObjectFactory2(TestObjectFactory): + FACTORY_FOR = TestObject + + three = 'three' + four = factory.LazyAttribute(lambda a: a.three + ' four') + + test_object = TestObjectFactory2.build() + self.assertEqual(test_object.one, 'one') + self.assertEqual(test_object.two, 'one two') + self.assertEqual(test_object.three, 'three') + self.assertEqual(test_object.four, 'three four') + + test_object_alt = TestObjectFactory.build() + self.assertEqual(None, test_object_alt.three) + + def testInheritanceWithInheritedClass(self): + class TestObjectFactory(factory.Factory): + one = 'one' + two = factory.LazyAttribute(lambda a: a.one + ' two') + + class TestFactory(TestObjectFactory): + three = 'three' + four = factory.LazyAttribute(lambda a: a.three + ' four') + + test_object = TestFactory.build() + self.assertEqual(test_object.one, 'one') + self.assertEqual(test_object.two, 'one two') + self.assertEqual(test_object.three, 'three') + self.assertEqual(test_object.four, 'three four') + + def testDualInheritance(self): + class TestObjectFactory(factory.Factory): + one = 'one' + + class TestOtherFactory(factory.Factory): + FACTORY_FOR = TestObject + two = 'two' + four = 'four' + + class TestFactory(TestObjectFactory, TestOtherFactory): + three = 'three' + + obj = TestFactory.build(two=2) + self.assertEqual('one', obj.one) + self.assertEqual(2, obj.two) + self.assertEqual('three', obj.three) + self.assertEqual('four', obj.four) + + def testSetCreationFunction(self): + def creation_function(class_to_create, **kwargs): + return "This doesn't even return an instance of {0}".format(class_to_create.__name__) + + class TestModelFactory(factory.Factory): + pass + + TestModelFactory.set_creation_function(creation_function) + + test_object = TestModelFactory.create() + self.assertEqual(test_object, "This doesn't even return an instance of TestModel") + + +class SubFactoryTestCase(unittest.TestCase): + def testSubFactory(self): + class TestModel2(FakeDjangoModel): + pass + + class TestModelFactory(factory.Factory): + FACTORY_FOR = TestModel + one = 3 + + class TestModel2Factory(factory.Factory): + FACTORY_FOR = TestModel2 + two = factory.SubFactory(TestModelFactory, one=1) + + test_model = TestModel2Factory(two__one=4) + self.assertEqual(4, test_model.two.one) + self.assertEqual(1, test_model.id) + self.assertEqual(1, test_model.two.id) + + def testSubFactoryWithLazyFields(self): + class TestModel2(FakeDjangoModel): + pass + + class TestModelFactory(factory.Factory): + FACTORY_FOR = TestModel + + class TestModel2Factory(factory.Factory): + FACTORY_FOR = TestModel2 + two = factory.SubFactory(TestModelFactory, + one=factory.Sequence(lambda n: 'x%sx' % n), + two=factory.LazyAttribute( + lambda o: '%s%s' % (o.one, o.one))) + + test_model = TestModel2Factory(one=42) + self.assertEqual('x0x', test_model.two.one) + self.assertEqual('x0xx0x', test_model.two.two) + + def testSubFactoryOverriding(self): + class TestObject(object): + def __init__(self, **kwargs): + for k, v in kwargs.iteritems(): + setattr(self, k, v) + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + class WrappingTestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + wrapped = factory.SubFactory(TestObjectFactory, two=2, four=4) + wrapped__two = 4 + wrapped__three = 3 + + wrapping = WrappingTestObjectFactory.build() + self.assertEqual(wrapping.wrapped.two, 4) + self.assertEqual(wrapping.wrapped.three, 3) + self.assertEqual(wrapping.wrapped.four, 4) + + + def testNestedSubFactory(self): + """Test nested sub-factories.""" + + class TestObject(object): + def __init__(self, **kwargs): + for k, v in kwargs.iteritems(): + setattr(self, k, v) + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + class WrappingTestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + wrapped = factory.SubFactory(TestObjectFactory) + wrapped_bis = factory.SubFactory(TestObjectFactory, one=1) + + class OuterWrappingTestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + wrap = factory.SubFactory(WrappingTestObjectFactory, wrapped__two=2) + + outer = OuterWrappingTestObjectFactory.build() + self.assertEqual(outer.wrap.wrapped.two, 2) + self.assertEqual(outer.wrap.wrapped_bis.one, 1) + + def testNestedSubFactoryWithOverriddenSubFactories(self): + """Test nested sub-factories, with attributes overridden with subfactories.""" + + class TestObject(object): + def __init__(self, **kwargs): + for k, v in kwargs.iteritems(): + setattr(self, k, v) + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + two = 'two' + + class WrappingTestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + wrapped = factory.SubFactory(TestObjectFactory) + friend = factory.LazyAttribute(lambda o: o.wrapped.two.four + 1) + + class OuterWrappingTestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + wrap = factory.SubFactory(WrappingTestObjectFactory, + wrapped__two=factory.SubFactory(TestObjectFactory, four=4)) + + outer = OuterWrappingTestObjectFactory.build() + self.assertEqual(outer.wrap.wrapped.two.four, 4) + self.assertEqual(outer.wrap.friend, 5) + + def testSubFactoryAndInheritance(self): + """Test inheriting from a factory with subfactories, overriding.""" + class TestObject(object): + def __init__(self, **kwargs): + for k, v in kwargs.iteritems(): + setattr(self, k, v) + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + two = 'two' + + class WrappingTestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + wrapped = factory.SubFactory(TestObjectFactory) + friend = factory.LazyAttribute(lambda o: o.wrapped.two + 1) + + class ExtendedWrappingTestObjectFactory(WrappingTestObjectFactory): + wrapped__two = 4 + + wrapping = ExtendedWrappingTestObjectFactory.build() + self.assertEqual(wrapping.wrapped.two, 4) + self.assertEqual(wrapping.friend, 5) + + def testDiamondSubFactory(self): + """Tests the case where an object has two fields with a common field.""" + class InnerMost(object): + def __init__(self, a, b): + self.a = a + self.b = b + + class SideA(object): + def __init__(self, inner_from_a): + self.inner_from_a = inner_from_a + + class SideB(object): + def __init__(self, inner_from_b): + self.inner_from_b = inner_from_b + + class OuterMost(object): + def __init__(self, foo, side_a, side_b): + self.foo = foo + self.side_a = side_a + self.side_b = side_b + + class InnerMostFactory(factory.Factory): + FACTORY_FOR = InnerMost + a = 15 + b = 20 + + class SideAFactory(factory.Factory): + FACTORY_FOR = SideA + inner_from_a = factory.SubFactory(InnerMostFactory, a=20) + + class SideBFactory(factory.Factory): + FACTORY_FOR = SideB + inner_from_b = factory.SubFactory(InnerMostFactory, b=15) + + class OuterMostFactory(factory.Factory): + FACTORY_FOR = OuterMost + + foo = 30 + side_a = factory.SubFactory(SideAFactory, + inner_from_a__a=factory.LazyContainerAttribute(lambda obj, containers: containers[1].foo * 2)) + side_b = factory.SubFactory(SideBFactory, + inner_from_b=factory.LazyContainerAttribute(lambda obj, containers: containers[0].side_a.inner_from_a)) + + outer = OuterMostFactory.build() + self.assertEqual(outer.foo, 30) + self.assertEqual(outer.side_a.inner_from_a, outer.side_b.inner_from_b) + self.assertEqual(outer.side_a.inner_from_a.a, outer.foo * 2) + self.assertEqual(outer.side_a.inner_from_a.b, 20) + + outer = OuterMostFactory.build(side_a__inner_from_a__b = 4) + self.assertEqual(outer.foo, 30) + self.assertEqual(outer.side_a.inner_from_a, outer.side_b.inner_from_b) + self.assertEqual(outer.side_a.inner_from_a.a, outer.foo * 2) + self.assertEqual(outer.side_a.inner_from_a.b, 4) + + +if __name__ == '__main__': + unittest.main() |