summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2012-01-12 08:48:34 -0700
committerCarl Meyer <carl@oddbird.net>2012-01-12 08:48:34 -0700
commit24b6a6b83cfb7cd5bab304bb8cc22383cf461d85 (patch)
tree3b3939aa09d32089fd8077c8eece8193642b262d
parent86393d4d1117426bc2aafbfb9f11f96c463f05f1 (diff)
parent363fa7b470286f2b38ab33a7e986bfd000f25d86 (diff)
downloadfactory-boy-24b6a6b83cfb7cd5bab304bb8cc22383cf461d85.tar
factory-boy-24b6a6b83cfb7cd5bab304bb8cc22383cf461d85.tar.gz
Merge branch 'master' into allow-public-classmethods
-rw-r--r--README.rst4
-rw-r--r--factory/__init__.py3
-rw-r--r--factory/containers.py30
-rw-r--r--factory/declarations.py49
-rw-r--r--tests/__init__.py1
-rw-r--r--tests/test_base.py364
-rw-r--r--tests/test_containers.py27
-rw-r--r--tests/test_using.py477
8 files changed, 574 insertions, 381 deletions
diff --git a/README.rst b/README.rst
index 7cd80f6..f20b129 100644
--- a/README.rst
+++ b/README.rst
@@ -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()