diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/__init__.py | 7 | ||||
-rw-r--r-- | tests/alter_time.py | 2 | ||||
-rw-r--r-- | tests/compat.py | 2 | ||||
-rw-r--r-- | tests/cyclic/bar.py | 5 | ||||
-rw-r--r-- | tests/cyclic/foo.py | 5 | ||||
-rw-r--r-- | tests/cyclic/self_ref.py | 37 | ||||
-rw-r--r-- | tests/djapp/models.py | 47 | ||||
-rw-r--r-- | tests/djapp/settings.py | 6 | ||||
-rw-r--r-- | tests/test_alchemy.py | 73 | ||||
-rw-r--r-- | tests/test_base.py | 266 | ||||
-rw-r--r-- | tests/test_containers.py | 105 | ||||
-rw-r--r-- | tests/test_declarations.py | 17 | ||||
-rw-r--r-- | tests/test_django.py | 391 | ||||
-rw-r--r-- | tests/test_faker.py | 135 | ||||
-rw-r--r-- | tests/test_fuzzy.py | 83 | ||||
-rw-r--r-- | tests/test_helpers.py | 2 | ||||
-rw-r--r-- | tests/test_mongoengine.py | 21 | ||||
-rw-r--r-- | tests/test_using.py | 551 | ||||
-rw-r--r-- | tests/test_utils.py | 16 | ||||
-rw-r--r-- | tests/testdata/__init__.py | 2 | ||||
-rw-r--r-- | tests/tools.py | 2 | ||||
-rw-r--r-- | tests/utils.py | 2 |
22 files changed, 1296 insertions, 481 deletions
diff --git a/tests/__init__.py b/tests/__init__.py index 5b6fc55..b2c772d 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 Raphaël Barrois + +# factory.django needs a configured Django. +from .test_django import * from .test_base import * from .test_containers import * from .test_declarations import * -from .test_django import * +from .test_faker import * from .test_fuzzy import * from .test_helpers import * from .test_using import * diff --git a/tests/alter_time.py b/tests/alter_time.py index db0a611..aa2db3b 100644 --- a/tests/alter_time.py +++ b/tests/alter_time.py @@ -7,7 +7,7 @@ from __future__ import print_function import datetime -import mock +from .compat import mock real_datetime_class = datetime.datetime diff --git a/tests/compat.py b/tests/compat.py index ff96f13..167c185 100644 --- a/tests/compat.py +++ b/tests/compat.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 diff --git a/tests/cyclic/bar.py b/tests/cyclic/bar.py index fed0602..b4f8e0c 100644 --- a/tests/cyclic/bar.py +++ b/tests/cyclic/bar.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -30,7 +30,8 @@ class Bar(object): class BarFactory(factory.Factory): - FACTORY_FOR = Bar + class Meta: + model = Bar y = 13 foo = factory.SubFactory('cyclic.foo.FooFactory') diff --git a/tests/cyclic/foo.py b/tests/cyclic/foo.py index e584ed1..62e58c0 100644 --- a/tests/cyclic/foo.py +++ b/tests/cyclic/foo.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -32,7 +32,8 @@ class Foo(object): class FooFactory(factory.Factory): - FACTORY_FOR = Foo + class Meta: + model = Foo x = 42 bar = factory.SubFactory(bar_mod.BarFactory) diff --git a/tests/cyclic/self_ref.py b/tests/cyclic/self_ref.py new file mode 100644 index 0000000..d98b3ab --- /dev/null +++ b/tests/cyclic/self_ref.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2011-2015 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. + +"""Helper to test circular factory dependencies.""" + +import factory + +class TreeElement(object): + def __init__(self, name, parent): + self.parent = parent + self.name = name + + +class TreeElementFactory(factory.Factory): + class Meta: + model = TreeElement + + name = factory.Sequence(lambda n: "tree%s" % n) + parent = factory.SubFactory('tests.cyclic.self_ref.TreeElementFactory') diff --git a/tests/djapp/models.py b/tests/djapp/models.py index a65b50a..cadefbc 100644 --- a/tests/djapp/models.py +++ b/tests/djapp/models.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -55,10 +55,28 @@ class ConcreteSon(AbstractBase): pass +class AbstractSon(AbstractBase): + class Meta: + abstract = True + + +class ConcreteGrandSon(AbstractSon): + pass + + class StandardSon(StandardModel): pass +class PointedModel(models.Model): + foo = models.CharField(max_length=20) + + +class PointingModel(models.Model): + foo = models.CharField(max_length=20) + pointed = models.OneToOneField(PointedModel, related_name='pointer', null=True) + + WITHFILE_UPLOAD_TO = 'django' WITHFILE_UPLOAD_DIR = os.path.join(settings.MEDIA_ROOT, WITHFILE_UPLOAD_TO) @@ -70,6 +88,7 @@ if Image is not None: # PIL is available class WithImage(models.Model): animage = models.ImageField(upload_to=WITHFILE_UPLOAD_TO) + size = models.IntegerField(default=0) else: class WithImage(models.Model): @@ -77,4 +96,28 @@ else: class WithSignals(models.Model): - foo = models.CharField(max_length=20)
\ No newline at end of file + foo = models.CharField(max_length=20) + + +class CustomManager(models.Manager): + + def create(self, arg=None, **kwargs): + return super(CustomManager, self).create(**kwargs) + + +class WithCustomManager(models.Model): + + foo = models.CharField(max_length=20) + + objects = CustomManager() + + +class AbstractWithCustomManager(models.Model): + custom_objects = CustomManager() + + class Meta: + abstract = True + + +class FromAbstractWithCustomManager(AbstractWithCustomManager): + pass diff --git a/tests/djapp/settings.py b/tests/djapp/settings.py index c1b79b0..1ef16d5 100644 --- a/tests/djapp/settings.py +++ b/tests/djapp/settings.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -34,6 +34,9 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', }, + 'replica': { + 'ENGINE': 'django.db.backends.sqlite3', + }, } @@ -41,5 +44,6 @@ INSTALLED_APPS = [ 'tests.djapp' ] +MIDDLEWARE_CLASSES = () SECRET_KEY = 'testing.' diff --git a/tests/test_alchemy.py b/tests/test_alchemy.py index 4255417..5d8f275 100644 --- a/tests/test_alchemy.py +++ b/tests/test_alchemy.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2013 Romain Command& +# Copyright (c) 2015 Romain Command& # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ import factory from .compat import unittest +import mock try: @@ -36,7 +37,8 @@ if sqlalchemy: else: class Fake(object): - FACTORY_SESSION = None + class Meta: + sqlalchemy_session = None models = Fake() models.StandardModel = Fake() @@ -46,16 +48,28 @@ else: class StandardFactory(SQLAlchemyModelFactory): - FACTORY_FOR = models.StandardModel - FACTORY_SESSION = models.session + class Meta: + model = models.StandardModel + sqlalchemy_session = models.session + + id = factory.Sequence(lambda n: n) + foo = factory.Sequence(lambda n: 'foo%d' % n) + + +class ForceFlushingStandardFactory(SQLAlchemyModelFactory): + class Meta: + model = models.StandardModel + sqlalchemy_session = mock.MagicMock() + force_flush = True id = factory.Sequence(lambda n: n) foo = factory.Sequence(lambda n: 'foo%d' % n) class NonIntegerPkFactory(SQLAlchemyModelFactory): - FACTORY_FOR = models.NonIntegerPk - FACTORY_SESSION = models.session + class Meta: + model = models.NonIntegerPk + sqlalchemy_session = models.session id = factory.Sequence(lambda n: 'foo%d' % n) @@ -66,7 +80,7 @@ class SQLAlchemyPkSequenceTestCase(unittest.TestCase): def setUp(self): super(SQLAlchemyPkSequenceTestCase, self).setUp() StandardFactory.reset_sequence(1) - NonIntegerPkFactory.FACTORY_SESSION.rollback() + NonIntegerPkFactory._meta.sqlalchemy_session.rollback() def test_pk_first(self): std = StandardFactory.build() @@ -85,18 +99,39 @@ class SQLAlchemyPkSequenceTestCase(unittest.TestCase): StandardFactory.reset_sequence() std2 = StandardFactory.create() - self.assertEqual('foo2', std2.foo) - self.assertEqual(2, std2.id) + self.assertEqual('foo0', std2.foo) + self.assertEqual(0, std2.id) def test_pk_force_value(self): std1 = StandardFactory.create(id=10) - self.assertEqual('foo1', std1.foo) # sequence was set before pk + self.assertEqual('foo1', std1.foo) # sequence and pk are unrelated self.assertEqual(10, std1.id) StandardFactory.reset_sequence() std2 = StandardFactory.create() - self.assertEqual('foo11', std2.foo) - self.assertEqual(11, std2.id) + self.assertEqual('foo0', std2.foo) # Sequence doesn't care about pk + self.assertEqual(0, std2.id) + + +@unittest.skipIf(sqlalchemy is None, "SQLalchemy not installed.") +class SQLAlchemyForceFlushTestCase(unittest.TestCase): + def setUp(self): + super(SQLAlchemyForceFlushTestCase, self).setUp() + ForceFlushingStandardFactory.reset_sequence(1) + ForceFlushingStandardFactory._meta.sqlalchemy_session.rollback() + ForceFlushingStandardFactory._meta.sqlalchemy_session.reset_mock() + + def test_force_flush_called(self): + self.assertFalse(ForceFlushingStandardFactory._meta.sqlalchemy_session.flush.called) + ForceFlushingStandardFactory.create() + self.assertTrue(ForceFlushingStandardFactory._meta.sqlalchemy_session.flush.called) + + def test_force_flush_not_called(self): + ForceFlushingStandardFactory._meta.force_flush = False + self.assertFalse(ForceFlushingStandardFactory._meta.sqlalchemy_session.flush.called) + ForceFlushingStandardFactory.create() + self.assertFalse(ForceFlushingStandardFactory._meta.sqlalchemy_session.flush.called) + ForceFlushingStandardFactory._meta.force_flush = True @unittest.skipIf(sqlalchemy is None, "SQLalchemy not installed.") @@ -104,26 +139,26 @@ class SQLAlchemyNonIntegerPkTestCase(unittest.TestCase): def setUp(self): super(SQLAlchemyNonIntegerPkTestCase, self).setUp() NonIntegerPkFactory.reset_sequence() - NonIntegerPkFactory.FACTORY_SESSION.rollback() + NonIntegerPkFactory._meta.sqlalchemy_session.rollback() def test_first(self): nonint = NonIntegerPkFactory.build() - self.assertEqual('foo1', nonint.id) + self.assertEqual('foo0', nonint.id) def test_many(self): nonint1 = NonIntegerPkFactory.build() nonint2 = NonIntegerPkFactory.build() - self.assertEqual('foo1', nonint1.id) - self.assertEqual('foo2', nonint2.id) + self.assertEqual('foo0', nonint1.id) + self.assertEqual('foo1', nonint2.id) def test_creation(self): nonint1 = NonIntegerPkFactory.create() - self.assertEqual('foo1', nonint1.id) + self.assertEqual('foo0', nonint1.id) NonIntegerPkFactory.reset_sequence() nonint2 = NonIntegerPkFactory.build() - self.assertEqual('foo1', nonint2.id) + self.assertEqual('foo0', nonint2.id) def test_force_pk(self): nonint1 = NonIntegerPkFactory.create(id='foo10') @@ -131,4 +166,4 @@ class SQLAlchemyNonIntegerPkTestCase(unittest.TestCase): NonIntegerPkFactory.reset_sequence() nonint2 = NonIntegerPkFactory.create() - self.assertEqual('foo1', nonint2.id) + self.assertEqual('foo0', nonint2.id) diff --git a/tests/test_base.py b/tests/test_base.py index 8cea6fc..24f64e5 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Copyright (c) 2010 Mark Sandstrom -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -49,11 +49,12 @@ class FakeDjangoModel(object): class FakeModelFactory(base.Factory): - ABSTRACT_FACTORY = True + class Meta: + abstract = True @classmethod - def _create(cls, target_class, *args, **kwargs): - return target_class.create(**kwargs) + def _create(cls, model_class, *args, **kwargs): + return model_class.create(**kwargs) class TestModel(FakeDjangoModel): @@ -67,18 +68,21 @@ class SafetyTestCase(unittest.TestCase): class AbstractFactoryTestCase(unittest.TestCase): def test_factory_for_optional(self): - """Ensure that FACTORY_FOR is optional for ABSTRACT_FACTORY.""" + """Ensure that model= is optional for abstract=True.""" class TestObjectFactory(base.Factory): - ABSTRACT_FACTORY = True + class Meta: + abstract = True - # Passed + self.assertTrue(TestObjectFactory._meta.abstract) + self.assertIsNone(TestObjectFactory._meta.model) def test_factory_for_and_abstract_factory_optional(self): - """Ensure that ABSTRACT_FACTORY is optional.""" + """Ensure that Meta.abstract is optional.""" class TestObjectFactory(base.Factory): pass - # passed + self.assertTrue(TestObjectFactory._meta.abstract) + self.assertIsNone(TestObjectFactory._meta.model) def test_abstract_factory_cannot_be_called(self): class TestObjectFactory(base.Factory): @@ -87,26 +91,155 @@ class AbstractFactoryTestCase(unittest.TestCase): self.assertRaises(base.FactoryError, TestObjectFactory.build) self.assertRaises(base.FactoryError, TestObjectFactory.create) + def test_abstract_factory_not_inherited(self): + """abstract=True isn't propagated to child classes.""" + + class TestObjectFactory(base.Factory): + class Meta: + abstract = True + model = TestObject + + class TestObjectChildFactory(TestObjectFactory): + pass + + self.assertFalse(TestObjectChildFactory._meta.abstract) + + def test_abstract_or_model_is_required(self): + class TestObjectFactory(base.Factory): + class Meta: + abstract = False + model = None + + self.assertRaises(base.FactoryError, TestObjectFactory.build) + self.assertRaises(base.FactoryError, TestObjectFactory.create) + + +class OptionsTests(unittest.TestCase): + def test_base_attrs(self): + class AbstractFactory(base.Factory): + pass + + # Declarative attributes + self.assertTrue(AbstractFactory._meta.abstract) + self.assertIsNone(AbstractFactory._meta.model) + self.assertEqual((), AbstractFactory._meta.inline_args) + self.assertEqual((), AbstractFactory._meta.exclude) + self.assertEqual(base.CREATE_STRATEGY, AbstractFactory._meta.strategy) + + # Non-declarative attributes + self.assertEqual({}, AbstractFactory._meta.declarations) + self.assertEqual({}, AbstractFactory._meta.postgen_declarations) + self.assertEqual(AbstractFactory, AbstractFactory._meta.factory) + self.assertEqual(base.Factory, AbstractFactory._meta.base_factory) + self.assertEqual(AbstractFactory, AbstractFactory._meta.counter_reference) + + def test_declaration_collecting(self): + lazy = declarations.LazyAttribute(lambda _o: 1) + postgen = declarations.PostGenerationDeclaration() + + class AbstractFactory(base.Factory): + x = 1 + y = lazy + z = postgen + + # Declarations aren't removed + self.assertEqual(1, AbstractFactory.x) + self.assertEqual(lazy, AbstractFactory.y) + self.assertEqual(postgen, AbstractFactory.z) + + # And are available in class Meta + self.assertEqual({'x': 1, 'y': lazy}, AbstractFactory._meta.declarations) + self.assertEqual({'z': postgen}, AbstractFactory._meta.postgen_declarations) + + def test_inherited_declaration_collecting(self): + lazy = declarations.LazyAttribute(lambda _o: 1) + lazy2 = declarations.LazyAttribute(lambda _o: 2) + postgen = declarations.PostGenerationDeclaration() + postgen2 = declarations.PostGenerationDeclaration() + + class AbstractFactory(base.Factory): + x = 1 + y = lazy + z = postgen + + class OtherFactory(AbstractFactory): + a = lazy2 + b = postgen2 + + # Declarations aren't removed + self.assertEqual(lazy2, OtherFactory.a) + self.assertEqual(postgen2, OtherFactory.b) + self.assertEqual(1, OtherFactory.x) + self.assertEqual(lazy, OtherFactory.y) + self.assertEqual(postgen, OtherFactory.z) + + # And are available in class Meta + self.assertEqual({'x': 1, 'y': lazy, 'a': lazy2}, OtherFactory._meta.declarations) + self.assertEqual({'z': postgen, 'b': postgen2}, OtherFactory._meta.postgen_declarations) + + def test_inherited_declaration_shadowing(self): + lazy = declarations.LazyAttribute(lambda _o: 1) + lazy2 = declarations.LazyAttribute(lambda _o: 2) + postgen = declarations.PostGenerationDeclaration() + postgen2 = declarations.PostGenerationDeclaration() + + class AbstractFactory(base.Factory): + x = 1 + y = lazy + z = postgen + + class OtherFactory(AbstractFactory): + y = lazy2 + z = postgen2 + + # Declarations aren't removed + self.assertEqual(1, OtherFactory.x) + self.assertEqual(lazy2, OtherFactory.y) + self.assertEqual(postgen2, OtherFactory.z) + + # And are available in class Meta + self.assertEqual({'x': 1, 'y': lazy2}, OtherFactory._meta.declarations) + self.assertEqual({'z': postgen2}, OtherFactory._meta.postgen_declarations) + + +class DeclarationParsingTests(unittest.TestCase): + def test_classmethod(self): + class TestObjectFactory(base.Factory): + class Meta: + model = TestObject + + @classmethod + def some_classmethod(cls): + return cls.create() + + self.assertTrue(hasattr(TestObjectFactory, 'some_classmethod')) + obj = TestObjectFactory.some_classmethod() + self.assertEqual(TestObject, obj.__class__) + class FactoryTestCase(unittest.TestCase): - def test_factory_for(self): + def test_magic_happens(self): + """Calling a FooFactory doesn't yield a FooFactory instance.""" class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject - self.assertEqual(TestObject, TestObjectFactory.FACTORY_FOR) + self.assertEqual(TestObject, TestObjectFactory._meta.model) obj = TestObjectFactory.build() - self.assertFalse(hasattr(obj, 'FACTORY_FOR')) + self.assertFalse(hasattr(obj, '_meta')) def test_display(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = FakeDjangoModel + class Meta: + model = FakeDjangoModel self.assertIn('TestObjectFactory', str(TestObjectFactory)) self.assertIn('FakeDjangoModel', str(TestObjectFactory)) def test_lazy_attribute_non_existent_param(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = declarations.LazyAttribute(lambda a: a.does_not_exist ) @@ -115,12 +248,14 @@ class FactoryTestCase(unittest.TestCase): def test_inheritance_with_sequence(self): """Tests that sequence IDs are shared between parent and son.""" class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = declarations.Sequence(lambda a: a) class TestSubFactory(TestObjectFactory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject pass @@ -137,7 +272,8 @@ class FactorySequenceTestCase(unittest.TestCase): super(FactorySequenceTestCase, self).setUp() class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = declarations.Sequence(lambda n: n) self.TestObjectFactory = TestObjectFactory @@ -212,16 +348,17 @@ class FactorySequenceTestCase(unittest.TestCase): class FactoryDefaultStrategyTestCase(unittest.TestCase): def setUp(self): - self.default_strategy = base.Factory.FACTORY_STRATEGY + self.default_strategy = base.Factory._meta.strategy def tearDown(self): - base.Factory.FACTORY_STRATEGY = self.default_strategy + base.Factory._meta.strategy = self.default_strategy def test_build_strategy(self): - base.Factory.FACTORY_STRATEGY = base.BUILD_STRATEGY + base.Factory._meta.strategy = base.BUILD_STRATEGY class TestModelFactory(base.Factory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -230,10 +367,11 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): self.assertFalse(test_model.id) def test_create_strategy(self): - # Default FACTORY_STRATEGY + # Default Meta.strategy class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -242,10 +380,11 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): self.assertTrue(test_model.id) def test_stub_strategy(self): - base.Factory.FACTORY_STRATEGY = base.STUB_STRATEGY + base.Factory._meta.strategy = base.STUB_STRATEGY class TestModelFactory(base.Factory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -254,42 +393,56 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): self.assertFalse(hasattr(test_model, 'id')) # We should have a plain old object def test_unknown_strategy(self): - base.Factory.FACTORY_STRATEGY = 'unknown' + base.Factory._meta.strategy = 'unknown' class TestModelFactory(base.Factory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' self.assertRaises(base.Factory.UnknownStrategy, TestModelFactory) - def test_stub_with_non_stub_strategy(self): + def test_stub_with_create_strategy(self): class TestModelFactory(base.StubFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' - TestModelFactory.FACTORY_STRATEGY = base.CREATE_STRATEGY + TestModelFactory._meta.strategy = base.CREATE_STRATEGY self.assertRaises(base.StubFactory.UnsupportedStrategy, TestModelFactory) - TestModelFactory.FACTORY_STRATEGY = base.BUILD_STRATEGY - self.assertRaises(base.StubFactory.UnsupportedStrategy, TestModelFactory) + def test_stub_with_build_strategy(self): + class TestModelFactory(base.StubFactory): + class Meta: + model = TestModel + + one = 'one' + + TestModelFactory._meta.strategy = base.BUILD_STRATEGY + obj = TestModelFactory() + + # For stubs, build() is an alias of stub(). + self.assertFalse(isinstance(obj, TestModel)) def test_change_strategy(self): @base.use_strategy(base.CREATE_STRATEGY) class TestModelFactory(base.StubFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' - self.assertEqual(base.CREATE_STRATEGY, TestModelFactory.FACTORY_STRATEGY) + self.assertEqual(base.CREATE_STRATEGY, TestModelFactory._meta.strategy) class FactoryCreationTestCase(unittest.TestCase): def test_factory_for(self): class TestFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject self.assertTrue(isinstance(TestFactory.build(), TestObject)) @@ -297,22 +450,41 @@ class FactoryCreationTestCase(unittest.TestCase): class TestFactory(base.StubFactory): pass - self.assertEqual(TestFactory.FACTORY_STRATEGY, base.STUB_STRATEGY) + self.assertEqual(TestFactory._meta.strategy, base.STUB_STRATEGY) def test_inheritance_with_stub(self): class TestObjectFactory(base.StubFactory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject pass class TestFactory(TestObjectFactory): pass - self.assertEqual(TestFactory.FACTORY_STRATEGY, base.STUB_STRATEGY) + self.assertEqual(TestFactory._meta.strategy, base.STUB_STRATEGY) + + def test_stub_and_subfactory(self): + class StubA(base.StubFactory): + class Meta: + model = TestObject + + one = 'blah' + + class StubB(base.StubFactory): + class Meta: + model = TestObject + + stubbed = declarations.SubFactory(StubA, two='two') + + b = StubB() + self.assertEqual('blah', b.stubbed.one) + self.assertEqual('two', b.stubbed.two) def test_custom_creation(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel @classmethod def _prepare(cls, create, **kwargs): @@ -335,28 +507,30 @@ class FactoryCreationTestCase(unittest.TestCase): class Test(base.Factory): pass - self.assertTrue(Test._abstract_factory) + self.assertTrue(Test._meta.abstract) class PostGenerationParsingTestCase(unittest.TestCase): def test_extraction(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject foo = declarations.PostGenerationDeclaration() - self.assertIn('foo', TestObjectFactory._postgen_declarations) + self.assertIn('foo', TestObjectFactory._meta.postgen_declarations) def test_classlevel_extraction(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject foo = declarations.PostGenerationDeclaration() foo__bar = 42 - self.assertIn('foo', TestObjectFactory._postgen_declarations) - self.assertIn('foo__bar', TestObjectFactory._declarations) + self.assertIn('foo', TestObjectFactory._meta.postgen_declarations) + self.assertIn('foo__bar', TestObjectFactory._meta.declarations) diff --git a/tests/test_containers.py b/tests/test_containers.py index 8b78dc7..083b306 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Copyright (c) 2010 Mark Sandstrom -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -94,111 +94,12 @@ class LazyStubTestCase(unittest.TestCase): class RandomObj(object): pass - stub = containers.LazyStub({'one': 1, 'two': 2}, target_class=RandomObj) + stub = containers.LazyStub({'one': 1, 'two': 2}, model_class=RandomObj) self.assertIn('RandomObj', repr(stub)) self.assertIn('RandomObj', str(stub)) self.assertIn('one', str(stub)) -class OrderedDeclarationMock(declarations.OrderedDeclaration): - pass - - -class DeclarationDictTestCase(unittest.TestCase): - def test_basics(self): - one = OrderedDeclarationMock() - two = 2 - three = OrderedDeclarationMock() - - d = containers.DeclarationDict(dict(one=one, two=two, three=three)) - - self.assertTrue('one' in d) - self.assertTrue('two' in d) - self.assertTrue('three' in d) - - self.assertEqual(one, d['one']) - self.assertEqual(two, d['two']) - self.assertEqual(three, d['three']) - - self.assertEqual(one, d.pop('one')) - self.assertFalse('one' in d) - - d['one'] = one - self.assertTrue('one' in d) - self.assertEqual(one, d['one']) - - self.assertEqual(set(['one', 'two', 'three']), - set(d)) - - def test_insert(self): - one = OrderedDeclarationMock() - two = 2 - three = OrderedDeclarationMock() - four = OrderedDeclarationMock() - - d = containers.DeclarationDict(dict(one=one, two=two, four=four)) - - self.assertEqual(set(['two', 'one', 'four']), set(d)) - - d['three'] = three - self.assertEqual(set(['two', 'one', 'three', 'four']), set(d)) - - def test_replace(self): - one = OrderedDeclarationMock() - two = 2 - three = OrderedDeclarationMock() - four = OrderedDeclarationMock() - - d = containers.DeclarationDict(dict(one=one, two=two, three=three)) - - self.assertEqual(set(['two', 'one', 'three']), set(d)) - - d['three'] = four - self.assertEqual(set(['two', 'one', 'three']), set(d)) - self.assertEqual(set([two, one, four]), set(d.values())) - - def test_copy(self): - one = OrderedDeclarationMock() - two = 2 - three = OrderedDeclarationMock() - four = OrderedDeclarationMock() - - d = containers.DeclarationDict(dict(one=one, two=two, three=three)) - d2 = d.copy({'five': 5}) - - self.assertEqual(5, d2['five']) - self.assertFalse('five' in d) - - d.pop('one') - self.assertEqual(one, d2['one']) - - d2['two'] = four - self.assertEqual(four, d2['two']) - self.assertEqual(two, d['two']) - - def test_update_with_public(self): - d = containers.DeclarationDict() - d.update_with_public({ - 'one': 1, - '_two': 2, - 'three': 3, - 'classmethod': classmethod(lambda c: 1), - 'staticmethod': staticmethod(lambda: 1), - }) - self.assertEqual(set(['one', 'three']), set(d)) - self.assertEqual(set([1, 3]), set(d.values())) - - def test_update_with_public_ignores_factory_attributes(self): - """Ensure that a DeclarationDict ignores FACTORY_ keys.""" - d = containers.DeclarationDict() - d.update_with_public({ - 'one': 1, - 'FACTORY_FOR': 2, - 'FACTORY_ARG_PARAMETERS': 3, - }) - self.assertEqual(['one'], list(d)) - self.assertEqual([1], list(d.values())) - class AttributeBuilderTestCase(unittest.TestCase): def test_empty(self): @@ -320,7 +221,7 @@ class AttributeBuilderTestCase(unittest.TestCase): class FakeFactory(object): @classmethod def declarations(cls, extra): - d = containers.DeclarationDict({'one': 1, 'two': la}) + d = {'one': 1, 'two': la} d.update(extra) return d diff --git a/tests/test_declarations.py b/tests/test_declarations.py index 86bc8b5..2601a38 100644 --- a/tests/test_declarations.py +++ b/tests/test_declarations.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Copyright (c) 2010 Mark Sandstrom -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -22,7 +22,6 @@ import datetime import itertools -import warnings from factory import declarations from factory import helpers @@ -207,20 +206,6 @@ class FactoryWrapperTestCase(unittest.TestCase): datetime.date = orig_date -class RelatedFactoryTestCase(unittest.TestCase): - - def test_deprecate_name(self): - with warnings.catch_warnings(record=True) as w: - - warnings.simplefilter('always') - f = declarations.RelatedFactory('datetime.date', name='blah') - - self.assertEqual('blah', f.name) - self.assertEqual(1, len(w)) - self.assertIn('RelatedFactory', str(w[0].message)) - self.assertIn('factory_related_name', str(w[0].message)) - - class PostGenerationMethodCallTestCase(unittest.TestCase): def setUp(self): self.obj = mock.MagicMock() diff --git a/tests/test_django.py b/tests/test_django.py index 50a67a3..103df91 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -21,9 +21,7 @@ """Tests for factory_boy/Django interactions.""" import os - -import factory -import factory.django +from .compat import is_python2, unittest, mock try: @@ -31,6 +29,28 @@ try: except ImportError: # pragma: no cover django = None +# Setup Django as soon as possible +if django is not None: + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tests.djapp.settings') + + if django.VERSION >= (1, 7, 0): + django.setup() + from django import test as django_test + from django.conf import settings + from django.db import models as django_models + if django.VERSION <= (1, 8, 0): + from django.test.simple import DjangoTestSuiteRunner + else: + from django.test.runner import DiscoverRunner as DjangoTestSuiteRunner + from django.test import utils as django_test_utils + from django.db.models import signals + from .djapp import models + +else: + django_test = unittest + + + try: from PIL import Image except ImportError: # pragma: no cover @@ -42,38 +62,13 @@ except ImportError: # pragma: no cover Image = None -from .compat import is_python2, unittest, mock +import factory +import factory.django + from . import testdata from . import tools -if django is not None: - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tests.djapp.settings') - - from django import test as django_test - from django.conf import settings - from django.db import models as django_models - from django.test import simple as django_test_simple - from django.test import utils as django_test_utils - from django.db.models import signals - from .djapp import models -else: # pragma: no cover - django_test = unittest - - class Fake(object): - pass - - models = Fake() - models.StandardModel = Fake - models.StandardSon = None - models.AbstractBase = Fake - models.ConcreteSon = Fake - models.NonIntegerPk = Fake - models.WithFile = Fake - models.WithImage = Fake - models.WithSignals = Fake - - test_state = {} @@ -81,7 +76,7 @@ def setUpModule(): if django is None: # pragma: no cover raise unittest.SkipTest("Django not installed") django_test_utils.setup_test_environment() - runner = django_test_simple.DjangoTestSuiteRunner() + runner = DjangoTestSuiteRunner() runner_state = runner.setup_databases() test_state.update({ 'runner': runner, @@ -98,54 +93,99 @@ def tearDownModule(): django_test_utils.teardown_test_environment() -class StandardFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.StandardModel +if django is not None: + class StandardFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.StandardModel + + foo = factory.Sequence(lambda n: "foo%d" % n) + + + class StandardFactoryWithPKField(factory.django.DjangoModelFactory): + class Meta: + model = models.StandardModel + django_get_or_create = ('pk',) + + foo = factory.Sequence(lambda n: "foo%d" % n) + pk = None + + + class NonIntegerPkFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.NonIntegerPk + + foo = factory.Sequence(lambda n: "foo%d" % n) + bar = '' - foo = factory.Sequence(lambda n: "foo%d" % n) + class AbstractBaseFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.AbstractBase + abstract = True -class StandardFactoryWithPKField(factory.django.DjangoModelFactory): - FACTORY_FOR = models.StandardModel - FACTORY_DJANGO_GET_OR_CREATE = ('pk',) + foo = factory.Sequence(lambda n: "foo%d" % n) - foo = factory.Sequence(lambda n: "foo%d" % n) - pk = None + class ConcreteSonFactory(AbstractBaseFactory): + class Meta: + model = models.ConcreteSon -class NonIntegerPkFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.NonIntegerPk - foo = factory.Sequence(lambda n: "foo%d" % n) - bar = '' + class AbstractSonFactory(AbstractBaseFactory): + class Meta: + model = models.AbstractSon -class AbstractBaseFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.AbstractBase - ABSTRACT_FACTORY = True + class ConcreteGrandSonFactory(AbstractBaseFactory): + class Meta: + model = models.ConcreteGrandSon - foo = factory.Sequence(lambda n: "foo%d" % n) + class WithFileFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.WithFile -class ConcreteSonFactory(AbstractBaseFactory): - FACTORY_FOR = models.ConcreteSon + if django is not None: + afile = factory.django.FileField() -class WithFileFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithFile + class WithImageFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.WithImage - if django is not None: - afile = factory.django.FileField() + if django is not None: + animage = factory.django.ImageField() -class WithImageFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithImage + class WithSignalsFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.WithSignals - if django is not None: - animage = factory.django.ImageField() + class WithCustomManagerFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.WithCustomManager -class WithSignalsFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithSignals + foo = factory.Sequence(lambda n: "foo%d" % n) + + +@unittest.skipIf(django is None, "Django not installed.") +class ModelTests(django_test.TestCase): + def test_unset_model(self): + class UnsetModelFactory(factory.django.DjangoModelFactory): + pass + + self.assertRaises(factory.FactoryError, UnsetModelFactory.create) + + def test_cross_database(self): + class OtherDBFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.StandardModel + database = 'replica' + + obj = OtherDBFactory() + self.assertFalse(models.StandardModel.objects.exists()) + self.assertEqual(obj, models.StandardModel.objects.using('replica').get()) @unittest.skipIf(django is None, "Django not installed.") @@ -156,32 +196,32 @@ class DjangoPkSequenceTestCase(django_test.TestCase): def test_pk_first(self): std = StandardFactory.build() - self.assertEqual('foo1', std.foo) + self.assertEqual('foo0', std.foo) def test_pk_many(self): std1 = StandardFactory.build() std2 = StandardFactory.build() - self.assertEqual('foo1', std1.foo) - self.assertEqual('foo2', std2.foo) + self.assertEqual('foo0', std1.foo) + self.assertEqual('foo1', std2.foo) def test_pk_creation(self): std1 = StandardFactory.create() - self.assertEqual('foo1', std1.foo) + self.assertEqual('foo0', std1.foo) self.assertEqual(1, std1.pk) StandardFactory.reset_sequence() std2 = StandardFactory.create() - self.assertEqual('foo2', std2.foo) + self.assertEqual('foo0', std2.foo) self.assertEqual(2, std2.pk) def test_pk_force_value(self): std1 = StandardFactory.create(pk=10) - self.assertEqual('foo1', std1.foo) # sequence was set before pk + self.assertEqual('foo0', std1.foo) # sequence is unrelated to pk self.assertEqual(10, std1.pk) StandardFactory.reset_sequence() std2 = StandardFactory.create() - self.assertEqual('foo11', std2.foo) + self.assertEqual('foo0', std2.foo) self.assertEqual(11, std2.pk) @@ -194,12 +234,12 @@ class DjangoPkForceTestCase(django_test.TestCase): def test_no_pk(self): std = StandardFactoryWithPKField() self.assertIsNotNone(std.pk) - self.assertEqual('foo1', std.foo) + self.assertEqual('foo0', std.foo) def test_force_pk(self): std = StandardFactoryWithPKField(pk=42) self.assertIsNotNone(std.pk) - self.assertEqual('foo1', std.foo) + self.assertEqual('foo0', std.foo) def test_reuse_pk(self): std1 = StandardFactoryWithPKField(foo='bar') @@ -212,17 +252,20 @@ class DjangoPkForceTestCase(django_test.TestCase): @unittest.skipIf(django is None, "Django not installed.") class DjangoModelLoadingTestCase(django_test.TestCase): - """Tests FACTORY_FOR = 'app.Model' pattern.""" + """Tests class Meta: + model = 'app.Model' pattern.""" def test_loading(self): class ExampleFactory(factory.DjangoModelFactory): - FACTORY_FOR = 'djapp.StandardModel' + class Meta: + model = 'djapp.StandardModel' - self.assertEqual(models.StandardModel, ExampleFactory._get_target_class()) + self.assertEqual(models.StandardModel, ExampleFactory._get_model_class()) def test_building(self): class ExampleFactory(factory.DjangoModelFactory): - FACTORY_FOR = 'djapp.StandardModel' + class Meta: + model = 'djapp.StandardModel' e = ExampleFactory.build() self.assertEqual(models.StandardModel, e.__class__) @@ -233,7 +276,8 @@ class DjangoModelLoadingTestCase(django_test.TestCase): See https://github.com/rbarrois/factory_boy/issues/109. """ class ExampleFactory(factory.DjangoModelFactory): - FACTORY_FOR = 'djapp.StandardModel' + class Meta: + model = 'djapp.StandardModel' class Example2Factory(ExampleFactory): pass @@ -247,14 +291,16 @@ class DjangoModelLoadingTestCase(django_test.TestCase): See https://github.com/rbarrois/factory_boy/issues/109. """ class ExampleFactory(factory.DjangoModelFactory): - FACTORY_FOR = 'djapp.StandardModel' + class Meta: + model = 'djapp.StandardModel' foo = factory.Sequence(lambda n: n) class Example2Factory(ExampleFactory): - FACTORY_FOR = 'djapp.StandardSon' + class Meta: + model = 'djapp.StandardSon' - self.assertEqual(models.StandardSon, Example2Factory._get_target_class()) + self.assertEqual(models.StandardSon, Example2Factory._get_model_class()) e1 = ExampleFactory.build() e2 = Example2Factory.build() @@ -262,9 +308,9 @@ class DjangoModelLoadingTestCase(django_test.TestCase): self.assertEqual(models.StandardModel, e1.__class__) self.assertEqual(models.StandardSon, e2.__class__) self.assertEqual(models.StandardModel, e3.__class__) - self.assertEqual(1, e1.foo) - self.assertEqual(2, e2.foo) - self.assertEqual(3, e3.foo) + self.assertEqual(0, e1.foo) + self.assertEqual(1, e2.foo) + self.assertEqual(2, e3.foo) @unittest.skipIf(django is None, "Django not installed.") @@ -275,23 +321,23 @@ class DjangoNonIntegerPkTestCase(django_test.TestCase): def test_first(self): nonint = NonIntegerPkFactory.build() - self.assertEqual('foo1', nonint.foo) + self.assertEqual('foo0', nonint.foo) def test_many(self): nonint1 = NonIntegerPkFactory.build() nonint2 = NonIntegerPkFactory.build() - self.assertEqual('foo1', nonint1.foo) - self.assertEqual('foo2', nonint2.foo) + self.assertEqual('foo0', nonint1.foo) + self.assertEqual('foo1', nonint2.foo) def test_creation(self): nonint1 = NonIntegerPkFactory.create() - self.assertEqual('foo1', nonint1.foo) - self.assertEqual('foo1', nonint1.pk) + self.assertEqual('foo0', nonint1.foo) + self.assertEqual('foo0', nonint1.pk) NonIntegerPkFactory.reset_sequence() nonint2 = NonIntegerPkFactory.build() - self.assertEqual('foo1', nonint2.foo) + self.assertEqual('foo0', nonint2.foo) def test_force_pk(self): nonint1 = NonIntegerPkFactory.create(pk='foo10') @@ -300,19 +346,50 @@ class DjangoNonIntegerPkTestCase(django_test.TestCase): NonIntegerPkFactory.reset_sequence() nonint2 = NonIntegerPkFactory.create() - self.assertEqual('foo1', nonint2.foo) - self.assertEqual('foo1', nonint2.pk) + self.assertEqual('foo0', nonint2.foo) + self.assertEqual('foo0', nonint2.pk) @unittest.skipIf(django is None, "Django not installed.") class DjangoAbstractBaseSequenceTestCase(django_test.TestCase): def test_auto_sequence(self): - with factory.debug(): - obj = ConcreteSonFactory() + """The sequence of the concrete son of an abstract model should be autonomous.""" + obj = ConcreteSonFactory() + self.assertEqual(1, obj.pk) + + def test_auto_sequence(self): + """The sequence of the concrete grandson of an abstract model should be autonomous.""" + obj = ConcreteGrandSonFactory() self.assertEqual(1, obj.pk) @unittest.skipIf(django is None, "Django not installed.") +class DjangoRelatedFieldTestCase(django_test.TestCase): + + @classmethod + def setUpClass(cls): + super(DjangoRelatedFieldTestCase, cls).setUpClass() + class PointedFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.PointedModel + foo = 'ahah' + + class PointerFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.PointingModel + pointed = factory.SubFactory(PointedFactory, foo='hihi') + foo = 'bar' + + cls.PointedFactory = PointedFactory + cls.PointerFactory = PointerFactory + + def test_direct_related_create(self): + ptr = self.PointerFactory() + self.assertEqual('hihi', ptr.pointed.foo) + self.assertEqual(ptr.pointed, models.PointedModel.objects.get()) + + +@unittest.skipIf(django is None, "Django not installed.") class DjangoFileFieldTestCase(unittest.TestCase): def tearDown(self): @@ -325,6 +402,9 @@ class DjangoFileFieldTestCase(unittest.TestCase): o = WithFileFactory.build() self.assertIsNone(o.pk) self.assertEqual(b'', o.afile.read()) + self.assertEqual('example.dat', o.afile.name) + + o.save() self.assertEqual('django/example.dat', o.afile.name) def test_default_create(self): @@ -336,19 +416,26 @@ class DjangoFileFieldTestCase(unittest.TestCase): def test_with_content(self): o = WithFileFactory.build(afile__data='foo') self.assertIsNone(o.pk) + + # Django only allocates the full path on save() + o.save() self.assertEqual(b'foo', o.afile.read()) self.assertEqual('django/example.dat', o.afile.name) def test_with_file(self): with open(testdata.TESTFILE_PATH, 'rb') as f: o = WithFileFactory.build(afile__from_file=f) - self.assertIsNone(o.pk) + o.save() + self.assertEqual(b'example_data\n', o.afile.read()) self.assertEqual('django/example.data', o.afile.name) def test_with_path(self): o = WithFileFactory.build(afile__from_path=testdata.TESTFILE_PATH) self.assertIsNone(o.pk) + + # Django only allocates the full path on save() + o.save() self.assertEqual(b'example_data\n', o.afile.read()) self.assertEqual('django/example.data', o.afile.name) @@ -358,7 +445,9 @@ class DjangoFileFieldTestCase(unittest.TestCase): afile__from_file=f, afile__from_path='' ) - self.assertIsNone(o.pk) + # Django only allocates the full path on save() + o.save() + self.assertEqual(b'example_data\n', o.afile.read()) self.assertEqual('django/example.data', o.afile.name) @@ -368,6 +457,9 @@ class DjangoFileFieldTestCase(unittest.TestCase): afile__from_file=None, ) self.assertIsNone(o.pk) + + # Django only allocates the full path on save() + o.save() self.assertEqual(b'example_data\n', o.afile.read()) self.assertEqual('django/example.data', o.afile.name) @@ -383,16 +475,24 @@ class DjangoFileFieldTestCase(unittest.TestCase): afile__filename='example.foo', ) self.assertIsNone(o.pk) + + # Django only allocates the full path on save() + o.save() self.assertEqual(b'example_data\n', o.afile.read()) self.assertEqual('django/example.foo', o.afile.name) def test_existing_file(self): o1 = WithFileFactory.build(afile__from_path=testdata.TESTFILE_PATH) + o1.save() + self.assertEqual('django/example.data', o1.afile.name) - o2 = WithFileFactory.build(afile=o1.afile) + o2 = WithFileFactory.build(afile__from_file=o1.afile) self.assertIsNone(o2.pk) + o2.save() + self.assertEqual(b'example_data\n', o2.afile.read()) - self.assertEqual('django/example_1.data', o2.afile.name) + self.assertNotEqual('django/example.data', o2.afile.name) + self.assertRegexpMatches(o2.afile.name, r'django/example_\w+.data') def test_no_file(self): o = WithFileFactory.build(afile=None) @@ -413,6 +513,8 @@ class DjangoImageFieldTestCase(unittest.TestCase): def test_default_build(self): o = WithImageFactory.build() self.assertIsNone(o.pk) + o.save() + self.assertEqual(100, o.animage.width) self.assertEqual(100, o.animage.height) self.assertEqual('django/example.jpg', o.animage.name) @@ -420,13 +522,28 @@ class DjangoImageFieldTestCase(unittest.TestCase): def test_default_create(self): o = WithImageFactory.create() self.assertIsNotNone(o.pk) + o.save() + self.assertEqual(100, o.animage.width) self.assertEqual(100, o.animage.height) self.assertEqual('django/example.jpg', o.animage.name) + def test_complex_create(self): + o = WithImageFactory.create( + size=10, + animage__filename=factory.Sequence(lambda n: 'img%d.jpg' % n), + __sequence=42, + animage__width=factory.SelfAttribute('..size'), + animage__height=factory.SelfAttribute('width'), + ) + self.assertIsNotNone(o.pk) + self.assertEqual('django/img42.jpg', o.animage.name) + def test_with_content(self): o = WithImageFactory.build(animage__width=13, animage__color='red') self.assertIsNone(o.pk) + o.save() + self.assertEqual(13, o.animage.width) self.assertEqual(13, o.animage.height) self.assertEqual('django/example.jpg', o.animage.name) @@ -440,20 +557,23 @@ class DjangoImageFieldTestCase(unittest.TestCase): def test_gif(self): o = WithImageFactory.build(animage__width=13, animage__color='blue', animage__format='GIF') self.assertIsNone(o.pk) + o.save() + self.assertEqual(13, o.animage.width) self.assertEqual(13, o.animage.height) self.assertEqual('django/example.jpg', o.animage.name) i = Image.open(os.path.join(settings.MEDIA_ROOT, o.animage.name)) - colors = i.getcolors() - # 169 pixels with color 190 from the GIF palette - self.assertEqual([(169, 190)], colors) + colors = i.convert('RGB').getcolors() + # 169 pixels with rgb(0, 0, 255) + self.assertEqual([(169, (0, 0, 255))], colors) self.assertEqual('GIF', i.format) def test_with_file(self): with open(testdata.TESTIMAGE_PATH, 'rb') as f: o = WithImageFactory.build(animage__from_file=f) - self.assertIsNone(o.pk) + o.save() + # Image file for a 42x42 green jpeg: 301 bytes long. self.assertEqual(301, len(o.animage.read())) self.assertEqual('django/example.jpeg', o.animage.name) @@ -461,6 +581,8 @@ class DjangoImageFieldTestCase(unittest.TestCase): def test_with_path(self): o = WithImageFactory.build(animage__from_path=testdata.TESTIMAGE_PATH) self.assertIsNone(o.pk) + o.save() + # Image file for a 42x42 green jpeg: 301 bytes long. self.assertEqual(301, len(o.animage.read())) self.assertEqual('django/example.jpeg', o.animage.name) @@ -471,7 +593,8 @@ class DjangoImageFieldTestCase(unittest.TestCase): animage__from_file=f, animage__from_path='' ) - self.assertIsNone(o.pk) + o.save() + # Image file for a 42x42 green jpeg: 301 bytes long. self.assertEqual(301, len(o.animage.read())) self.assertEqual('django/example.jpeg', o.animage.name) @@ -482,6 +605,8 @@ class DjangoImageFieldTestCase(unittest.TestCase): animage__from_file=None, ) self.assertIsNone(o.pk) + o.save() + # Image file for a 42x42 green jpeg: 301 bytes long. self.assertEqual(301, len(o.animage.read())) self.assertEqual('django/example.jpeg', o.animage.name) @@ -498,18 +623,24 @@ class DjangoImageFieldTestCase(unittest.TestCase): animage__filename='example.foo', ) self.assertIsNone(o.pk) + o.save() + # Image file for a 42x42 green jpeg: 301 bytes long. self.assertEqual(301, len(o.animage.read())) self.assertEqual('django/example.foo', o.animage.name) def test_existing_file(self): o1 = WithImageFactory.build(animage__from_path=testdata.TESTIMAGE_PATH) + o1.save() - o2 = WithImageFactory.build(animage=o1.animage) + o2 = WithImageFactory.build(animage__from_file=o1.animage) self.assertIsNone(o2.pk) + o2.save() + # Image file for a 42x42 green jpeg: 301 bytes long. self.assertEqual(301, len(o2.animage.read())) - self.assertEqual('django/example_1.jpeg', o2.animage.name) + self.assertNotEqual('django/example.jpeg', o2.animage.name) + self.assertRegexpMatches(o2.animage.name, r'django/example_\w+.jpeg') def test_no_file(self): o = WithImageFactory.build(animage=None) @@ -547,10 +678,24 @@ class PreventSignalsTestCase(unittest.TestCase): self.assertSignalsReactivated() + def test_signal_cache(self): + with factory.django.mute_signals(signals.pre_save, signals.post_save): + signals.post_save.connect(self.handlers.mute_block_receiver) + WithSignalsFactory() + + self.assertTrue(self.handlers.mute_block_receiver.call_count, 1) + self.assertEqual(self.handlers.pre_init.call_count, 1) + self.assertFalse(self.handlers.pre_save.called) + self.assertFalse(self.handlers.post_save.called) + + self.assertSignalsReactivated() + self.assertTrue(self.handlers.mute_block_receiver.call_count, 1) + def test_class_decorator(self): @factory.django.mute_signals(signals.pre_save, signals.post_save) class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithSignals + class Meta: + model = models.WithSignals WithSignalsDecoratedFactory() @@ -560,10 +705,32 @@ class PreventSignalsTestCase(unittest.TestCase): self.assertSignalsReactivated() + def test_class_decorator_with_subfactory(self): + @factory.django.mute_signals(signals.pre_save, signals.post_save) + class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.WithSignals + + @factory.post_generation + def post(obj, create, extracted, **kwargs): + if not extracted: + WithSignalsDecoratedFactory.create(post=42) + + # This will disable the signals (twice), create two objects, + # and reactivate the signals. + WithSignalsDecoratedFactory() + + self.assertEqual(self.handlers.pre_init.call_count, 2) + self.assertFalse(self.handlers.pre_save.called) + self.assertFalse(self.handlers.post_save.called) + + self.assertSignalsReactivated() + def test_class_decorator_build(self): @factory.django.mute_signals(signals.pre_save, signals.post_save) class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithSignals + class Meta: + model = models.WithSignals WithSignalsDecoratedFactory.build() @@ -601,5 +768,21 @@ class PreventSignalsTestCase(unittest.TestCase): self.assertSignalsReactivated() +@unittest.skipIf(django is None, "Django not installed.") +class DjangoCustomManagerTestCase(unittest.TestCase): + + def test_extra_args(self): + # Our CustomManager will remove the 'arg=' argument. + model = WithCustomManagerFactory(arg='foo') + + def test_with_manager_on_abstract(self): + class ObjFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.FromAbstractWithCustomManager + + # Our CustomManager will remove the 'arg=' argument, + # invalid for the actual model. + ObjFactory.create(arg='invalid') + if __name__ == '__main__': # pragma: no cover unittest.main() diff --git a/tests/test_faker.py b/tests/test_faker.py new file mode 100644 index 0000000..99e54af --- /dev/null +++ b/tests/test_faker.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2010 Mark Sandstrom +# Copyright (c) 2011-2015 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. + + +import unittest + +import faker.providers + +import factory + + +class MockFaker(object): + def __init__(self, expected): + self.expected = expected + + def format(self, provider, **kwargs): + return self.expected[provider] + + +class FakerTests(unittest.TestCase): + def setUp(self): + self._real_fakers = factory.Faker._FAKER_REGISTRY + factory.Faker._FAKER_REGISTRY = {} + + def tearDown(self): + factory.Faker._FAKER_REGISTRY = self._real_fakers + + def _setup_mock_faker(self, locale=None, **definitions): + if locale is None: + locale = factory.Faker._DEFAULT_LOCALE + factory.Faker._FAKER_REGISTRY[locale] = MockFaker(definitions) + + def test_simple_biased(self): + self._setup_mock_faker(name="John Doe") + faker_field = factory.Faker('name') + self.assertEqual("John Doe", faker_field.generate({})) + + def test_full_factory(self): + class Profile(object): + def __init__(self, first_name, last_name, email): + self.first_name = first_name + self.last_name = last_name + self.email = email + + class ProfileFactory(factory.Factory): + class Meta: + model = Profile + first_name = factory.Faker('first_name') + last_name = factory.Faker('last_name', locale='fr_FR') + email = factory.Faker('email') + + self._setup_mock_faker(first_name="John", last_name="Doe", email="john.doe@example.org") + self._setup_mock_faker(first_name="Jean", last_name="Valjean", email="jvaljean@exemple.fr", locale='fr_FR') + + profile = ProfileFactory() + self.assertEqual("John", profile.first_name) + self.assertEqual("Valjean", profile.last_name) + self.assertEqual('john.doe@example.org', profile.email) + + def test_override_locale(self): + class Profile(object): + def __init__(self, first_name, last_name): + self.first_name = first_name + self.last_name = last_name + + class ProfileFactory(factory.Factory): + class Meta: + model = Profile + + first_name = factory.Faker('first_name') + last_name = factory.Faker('last_name', locale='fr_FR') + + self._setup_mock_faker(first_name="John", last_name="Doe") + self._setup_mock_faker(first_name="Jean", last_name="Valjean", locale='fr_FR') + self._setup_mock_faker(first_name="Johannes", last_name="Brahms", locale='de_DE') + + profile = ProfileFactory() + self.assertEqual("John", profile.first_name) + self.assertEqual("Valjean", profile.last_name) + + with factory.Faker.override_default_locale('de_DE'): + profile = ProfileFactory() + self.assertEqual("Johannes", profile.first_name) + self.assertEqual("Valjean", profile.last_name) + + profile = ProfileFactory() + self.assertEqual("John", profile.first_name) + self.assertEqual("Valjean", profile.last_name) + + def test_add_provider(self): + class Face(object): + def __init__(self, smiley, french_smiley): + self.smiley = smiley + self.french_smiley = french_smiley + + class FaceFactory(factory.Factory): + class Meta: + model = Face + + smiley = factory.Faker('smiley') + french_smiley = factory.Faker('smiley', locale='fr_FR') + + class SmileyProvider(faker.providers.BaseProvider): + def smiley(self): + return ':)' + + class FrenchSmileyProvider(faker.providers.BaseProvider): + def smiley(self): + return '(:' + + factory.Faker.add_provider(SmileyProvider) + factory.Faker.add_provider(FrenchSmileyProvider, 'fr_FR') + + face = FaceFactory() + self.assertEqual(":)", face.smiley) + self.assertEqual("(:", face.french_smiley) diff --git a/tests/test_fuzzy.py b/tests/test_fuzzy.py index 1caeb0a..4c3873a 100644 --- a/tests/test_fuzzy.py +++ b/tests/test_fuzzy.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Copyright (c) 2010 Mark Sandstrom -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -55,7 +55,7 @@ class FuzzyChoiceTestCase(unittest.TestCase): d = fuzzy.FuzzyChoice(options) - with mock.patch('random.choice', fake_choice): + with mock.patch('factory.fuzzy._random.choice', fake_choice): res = d.evaluate(2, None, False) self.assertEqual(6, res) @@ -74,6 +74,24 @@ class FuzzyChoiceTestCase(unittest.TestCase): res = d.evaluate(2, None, False) self.assertIn(res, [0, 1, 2]) + def test_lazy_generator(self): + class Gen(object): + def __init__(self, options): + self.options = options + self.unrolled = False + + def __iter__(self): + self.unrolled = True + return iter(self.options) + + opts = Gen([1, 2, 3]) + d = fuzzy.FuzzyChoice(opts) + self.assertFalse(opts.unrolled) + + res = d.evaluate(2, None, False) + self.assertIn(res, [1, 2, 3]) + self.assertTrue(opts.unrolled) + class FuzzyIntegerTestCase(unittest.TestCase): def test_definition(self): @@ -93,7 +111,7 @@ class FuzzyIntegerTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyInteger(2, 8) - with mock.patch('random.randrange', fake_randrange): + with mock.patch('factory.fuzzy._random.randrange', fake_randrange): res = fuzz.evaluate(2, None, False) self.assertEqual((2 + 8 + 1) * 1, res) @@ -103,7 +121,7 @@ class FuzzyIntegerTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyInteger(8) - with mock.patch('random.randrange', fake_randrange): + with mock.patch('factory.fuzzy._random.randrange', fake_randrange): res = fuzz.evaluate(2, None, False) self.assertEqual((0 + 8 + 1) * 1, res) @@ -113,7 +131,7 @@ class FuzzyIntegerTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyInteger(5, 8, 3) - with mock.patch('random.randrange', fake_randrange): + with mock.patch('factory.fuzzy._random.randrange', fake_randrange): res = fuzz.evaluate(2, None, False) self.assertEqual((5 + 8 + 1) * 3, res) @@ -146,7 +164,7 @@ class FuzzyDecimalTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyDecimal(2.0, 8.0) - with mock.patch('random.uniform', fake_uniform): + with mock.patch('factory.fuzzy._random.uniform', fake_uniform): res = fuzz.evaluate(2, None, False) self.assertEqual(decimal.Decimal('10.0'), res) @@ -156,7 +174,7 @@ class FuzzyDecimalTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyDecimal(8.0) - with mock.patch('random.uniform', fake_uniform): + with mock.patch('factory.fuzzy._random.uniform', fake_uniform): res = fuzz.evaluate(2, None, False) self.assertEqual(decimal.Decimal('8.0'), res) @@ -166,11 +184,24 @@ class FuzzyDecimalTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyDecimal(8.0, precision=3) - with mock.patch('random.uniform', fake_uniform): + with mock.patch('factory.fuzzy._random.uniform', fake_uniform): res = fuzz.evaluate(2, None, False) self.assertEqual(decimal.Decimal('8.001').quantize(decimal.Decimal(10) ** -3), res) + @unittest.skipIf(compat.PY2, "decimal.FloatOperation was added in Py3") + def test_no_approximation(self): + """We should not go through floats in our fuzzy calls unless actually needed.""" + fuzz = fuzzy.FuzzyDecimal(0, 10) + + decimal_context = decimal.getcontext() + old_traps = decimal_context.traps[decimal.FloatOperation] + try: + decimal_context.traps[decimal.FloatOperation] = True + fuzz.evaluate(2, None, None) + finally: + decimal_context.traps[decimal.FloatOperation] = old_traps + class FuzzyDateTestCase(unittest.TestCase): @classmethod @@ -214,7 +245,7 @@ class FuzzyDateTestCase(unittest.TestCase): fake_randint = lambda low, high: (low + high) // 2 fuzz = fuzzy.FuzzyDate(self.jan1, self.jan31) - with mock.patch('random.randint', fake_randint): + with mock.patch('factory.fuzzy._random.randint', fake_randint): res = fuzz.evaluate(2, None, False) self.assertEqual(datetime.date(2013, 1, 16), res) @@ -225,7 +256,7 @@ class FuzzyDateTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyDate(self.jan1) fake_randint = lambda low, high: (low + high) // 2 - with mock.patch('random.randint', fake_randint): + with mock.patch('factory.fuzzy._random.randint', fake_randint): res = fuzz.evaluate(2, None, False) self.assertEqual(datetime.date(2013, 1, 2), res) @@ -332,7 +363,7 @@ class FuzzyNaiveDateTimeTestCase(unittest.TestCase): fake_randint = lambda low, high: (low + high) // 2 fuzz = fuzzy.FuzzyNaiveDateTime(self.jan1, self.jan31) - with mock.patch('random.randint', fake_randint): + with mock.patch('factory.fuzzy._random.randint', fake_randint): res = fuzz.evaluate(2, None, False) self.assertEqual(datetime.datetime(2013, 1, 16), res) @@ -343,7 +374,7 @@ class FuzzyNaiveDateTimeTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyNaiveDateTime(self.jan1) fake_randint = lambda low, high: (low + high) // 2 - with mock.patch('random.randint', fake_randint): + with mock.patch('factory.fuzzy._random.randint', fake_randint): res = fuzz.evaluate(2, None, False) self.assertEqual(datetime.datetime(2013, 1, 2), res) @@ -450,7 +481,7 @@ class FuzzyDateTimeTestCase(unittest.TestCase): fake_randint = lambda low, high: (low + high) // 2 fuzz = fuzzy.FuzzyDateTime(self.jan1, self.jan31) - with mock.patch('random.randint', fake_randint): + with mock.patch('factory.fuzzy._random.randint', fake_randint): res = fuzz.evaluate(2, None, False) self.assertEqual(datetime.datetime(2013, 1, 16, tzinfo=compat.UTC), res) @@ -461,7 +492,7 @@ class FuzzyDateTimeTestCase(unittest.TestCase): fuzz = fuzzy.FuzzyDateTime(self.jan1) fake_randint = lambda low, high: (low + high) // 2 - with mock.patch('random.randint', fake_randint): + with mock.patch('factory.fuzzy._random.randint', fake_randint): res = fuzz.evaluate(2, None, False) self.assertEqual(datetime.datetime(2013, 1, 2, tzinfo=compat.UTC), res) @@ -486,7 +517,7 @@ class FuzzyTextTestCase(unittest.TestCase): chars = ['a', 'b', 'c'] fuzz = fuzzy.FuzzyText(prefix='pre', suffix='post', chars=chars, length=4) - with mock.patch('random.choice', fake_choice): + with mock.patch('factory.fuzzy._random.choice', fake_choice): res = fuzz.evaluate(2, None, False) self.assertEqual('preaaaapost', res) @@ -504,3 +535,25 @@ class FuzzyTextTestCase(unittest.TestCase): for char in res: self.assertIn(char, ['a', 'b', 'c']) + + +class FuzzyRandomTestCase(unittest.TestCase): + def test_seeding(self): + fuzz = fuzzy.FuzzyInteger(1, 1000) + + fuzzy.reseed_random(42) + value = fuzz.evaluate(sequence=1, obj=None, create=False) + + fuzzy.reseed_random(42) + value2 = fuzz.evaluate(sequence=1, obj=None, create=False) + self.assertEqual(value, value2) + + def test_reset_state(self): + fuzz = fuzzy.FuzzyInteger(1, 1000) + + state = fuzzy.get_random_state() + value = fuzz.evaluate(sequence=1, obj=None, create=False) + + fuzzy.set_random_state(state) + value2 = fuzz.evaluate(sequence=1, obj=None, create=False) + self.assertEqual(value, value2) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index f5a66e5..bee66ca 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Copyright (c) 2010 Mark Sandstrom -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 diff --git a/tests/test_mongoengine.py b/tests/test_mongoengine.py index 803607a..148d274 100644 --- a/tests/test_mongoengine.py +++ b/tests/test_mongoengine.py @@ -31,6 +31,9 @@ try: except ImportError: mongoengine = None +if os.environ.get('SKIP_MONGOENGINE') == '1': + mongoengine = None + if mongoengine: from factory.mongoengine import MongoEngineFactory @@ -42,12 +45,14 @@ if mongoengine: address = mongoengine.EmbeddedDocumentField(Address) class AddressFactory(MongoEngineFactory): - FACTORY_FOR = Address + class Meta: + model = Address street = factory.Sequence(lambda n: 'street%d' % n) class PersonFactory(MongoEngineFactory): - FACTORY_FOR = Person + class Meta: + model = Person name = factory.Sequence(lambda n: 'name%d' % n) address = factory.SubFactory(AddressFactory) @@ -59,10 +64,20 @@ class MongoEngineTestCase(unittest.TestCase): db_name = os.environ.get('MONGO_DATABASE', 'factory_boy_test') db_host = os.environ.get('MONGO_HOST', 'localhost') db_port = int(os.environ.get('MONGO_PORT', '27017')) + server_timeout_ms = int(os.environ.get('MONGO_TIMEOUT', '300')) @classmethod def setUpClass(cls): - cls.db = mongoengine.connect(cls.db_name, host=cls.db_host, port=cls.db_port) + from pymongo import read_preferences as mongo_rp + cls.db = mongoengine.connect( + db=cls.db_name, + host=cls.db_host, + port=cls.db_port, + # PyMongo>=2.1 requires an explicit read_preference. + read_preference=mongo_rp.ReadPreference.PRIMARY, + # PyMongo>=2.1 has a 20s timeout, use 100ms instead + serverselectiontimeoutms=cls.server_timeout_ms, + ) @classmethod def tearDownClass(cls): diff --git a/tests/test_using.py b/tests/test_using.py index 3979cd0..0a893c1 100644 --- a/tests/test_using.py +++ b/tests/test_using.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -69,6 +69,9 @@ class FakeModel(object): def order_by(self, *args, **kwargs): return [1] + def using(self, db): + return self + objects = FakeModelManager() def __init__(self, **kwargs): @@ -78,11 +81,12 @@ class FakeModel(object): class FakeModelFactory(factory.Factory): - ABSTRACT_FACTORY = True + class Meta: + abstract = True @classmethod - def _create(cls, target_class, *args, **kwargs): - return target_class.create(**kwargs) + def _create(cls, model_class, *args, **kwargs): + return model_class.create(**kwargs) class TestModel(FakeModel): @@ -292,17 +296,19 @@ class SimpleBuildTestCase(unittest.TestCase): class UsingFactoryTestCase(unittest.TestCase): def test_attribute(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 'one' test_object = TestObjectFactory.build() self.assertEqual(test_object.one, 'one') - def test_inheriting_target_class(self): + def test_inheriting_model_class(self): @factory.use_strategy(factory.BUILD_STRATEGY) class TestObjectFactory(factory.Factory, TestObject): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 'one' @@ -311,18 +317,22 @@ class UsingFactoryTestCase(unittest.TestCase): def test_abstract(self): class SomeAbstractFactory(factory.Factory): - ABSTRACT_FACTORY = True + class Meta: + abstract = True + one = 'one' class InheritedFactory(SomeAbstractFactory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject test_object = InheritedFactory.build() self.assertEqual(test_object.one, 'one') def test_sequence(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -337,7 +347,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_custom_begin(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject @classmethod def _setup_next_sequence(cls): @@ -356,7 +367,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_override(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Sequence(lambda n: 'one%d' % n) @@ -372,13 +384,14 @@ class UsingFactoryTestCase(unittest.TestCase): def test_custom_create(self): class TestModelFactory(factory.Factory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel two = 2 @classmethod - def _create(cls, target_class, *args, **kwargs): - obj = target_class.create(**kwargs) + def _create(cls, model_class, *args, **kwargs): + obj = model_class.create(**kwargs) obj.properly_created = True return obj @@ -395,7 +408,8 @@ class UsingFactoryTestCase(unittest.TestCase): self.y = y class NonDjangoFactory(factory.Factory): - FACTORY_FOR = NonDjango + class Meta: + model = NonDjango x = 3 @@ -405,7 +419,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_batch(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -420,7 +435,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.LazyAttribute(lambda a: 'abc' ) two = factory.LazyAttribute(lambda a: a.one + ' xyz') @@ -431,7 +447,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_sequence(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.LazyAttributeSequence(lambda a, n: 'abc%d' % n) two = factory.LazyAttributeSequence(lambda a, n: a.one + ' xyz%d' % n) @@ -446,7 +463,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_decorator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject @factory.lazy_attribute def one(a): @@ -460,7 +478,8 @@ class UsingFactoryTestCase(unittest.TestCase): n = 3 class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 'xx' two = factory.SelfAttribute('one') @@ -479,12 +498,14 @@ class UsingFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 3 three = factory.SelfAttribute('..bar') class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + model = TestModel2 bar = 4 two = factory.SubFactory(TestModelFactory, one=1) @@ -493,7 +514,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_decorator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject @factory.sequence def one(n): @@ -504,7 +526,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_sequence_decorator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject @factory.lazy_attribute_sequence def one(a, n): @@ -519,7 +542,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_build_with_parameters(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -535,7 +559,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -545,7 +570,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_create_batch(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -561,7 +587,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_build(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -571,7 +598,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -581,7 +609,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_stub(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -591,7 +620,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_build(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -607,7 +637,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -623,7 +654,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_stub(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -639,7 +671,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_build(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -649,7 +682,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -659,7 +693,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_batch_build(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -675,7 +710,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_batch_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 'one' @@ -691,7 +727,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_stub_batch(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') @@ -710,13 +747,15 @@ class UsingFactoryTestCase(unittest.TestCase): def test_inheritance(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject three = 'three' four = factory.LazyAttribute(lambda a: a.three + ' four') @@ -730,15 +769,48 @@ class UsingFactoryTestCase(unittest.TestCase): test_object_alt = TestObjectFactory.build() self.assertEqual(None, test_object_alt.three) + def test_override_inherited(self): + """Overriding inherited declarations""" + class TestObjectFactory(factory.Factory): + class Meta: + model = TestObject + + one = 'one' + + class TestObjectFactory2(TestObjectFactory): + one = 'two' + + test_object = TestObjectFactory2.build() + self.assertEqual('two', test_object.one) + + def test_override_inherited_deep(self): + """Overriding inherited declarations""" + class TestObjectFactory(factory.Factory): + class Meta: + model = TestObject + + one = 'one' + + class TestObjectFactory2(TestObjectFactory): + one = 'two' + + class TestObjectFactory3(TestObjectFactory2): + pass + + test_object = TestObjectFactory3.build() + self.assertEqual('two', test_object.one) + def test_inheritance_and_sequences(self): """Sequence counters should be kept within an inheritance chain.""" class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -755,12 +827,14 @@ class UsingFactoryTestCase(unittest.TestCase): pass class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject2 + class Meta: + model = TestObject2 to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -785,12 +859,14 @@ class UsingFactoryTestCase(unittest.TestCase): self.one = one class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject2 + class Meta: + model = TestObject2 to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -804,7 +880,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_inheritance_with_inherited_class(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') @@ -821,12 +898,14 @@ class UsingFactoryTestCase(unittest.TestCase): def test_dual_inheritance(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 'one' class TestOtherFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject two = 'two' four = 'four' @@ -841,7 +920,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_class_method_accessible(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject @classmethod def alt_create(cls, **kwargs): @@ -851,7 +931,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_static_method_accessible(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject @staticmethod def alt_create(**kwargs): @@ -859,15 +940,16 @@ class UsingFactoryTestCase(unittest.TestCase): self.assertEqual(TestObjectFactory.alt_create(foo=1), {"foo": 1}) - def test_arg_parameters(self): + def test_inline_args(self): class TestObject(object): def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_ARG_PARAMETERS = ('x', 'y') + class Meta: + model = TestObject + inline_args = ('x', 'y') x = 1 y = 2 @@ -878,15 +960,16 @@ class UsingFactoryTestCase(unittest.TestCase): self.assertEqual((42, 2), obj.args) self.assertEqual({'z': 5, 't': 4}, obj.kwargs) - def test_hidden_args(self): + def test_exclude(self): class TestObject(object): def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_HIDDEN_ARGS = ('x', 'z') + class Meta: + model = TestObject + exclude = ('x', 'z') x = 1 y = 2 @@ -897,16 +980,17 @@ class UsingFactoryTestCase(unittest.TestCase): self.assertEqual((), obj.args) self.assertEqual({'y': 2, 't': 4}, obj.kwargs) - def test_hidden_args_and_arg_parameters(self): + def test_exclude_and_inline_args(self): class TestObject(object): def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_HIDDEN_ARGS = ('x', 'z') - FACTORY_ARG_PARAMETERS = ('y',) + class Meta: + model = TestObject + exclude = ('x', 'z') + inline_args = ('y',) x = 1 y = 2 @@ -927,8 +1011,9 @@ class NonKwargParametersTestCase(unittest.TestCase): self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_ARG_PARAMETERS = ('one', 'two',) + class Meta: + model = TestObject + inline_args = ('one', 'two',) one = 1 two = 2 @@ -952,16 +1037,17 @@ class NonKwargParametersTestCase(unittest.TestCase): return inst class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_ARG_PARAMETERS = ('one', 'two') + class Meta: + model = TestObject + inline_args = ('one', 'two') one = 1 two = 2 three = 3 @classmethod - def _create(cls, target_class, *args, **kwargs): - return target_class.create(*args, **kwargs) + def _create(cls, model_class, *args, **kwargs): + return model_class.create(*args, **kwargs) obj = TestObjectFactory.create() self.assertEqual((1, 2), obj.args) @@ -978,7 +1064,8 @@ class KwargAdjustTestCase(unittest.TestCase): self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject @classmethod def _adjust_kwargs(cls, **kwargs): @@ -989,6 +1076,21 @@ class KwargAdjustTestCase(unittest.TestCase): self.assertEqual({'x': 1, 'y': 2, 'z': 3, 'foo': 3}, obj.kwargs) self.assertEqual((), obj.args) + def test_rename(self): + class TestObject(object): + def __init__(self, attributes=None): + self.attributes = attributes + + class TestObjectFactory(factory.Factory): + class Meta: + model = TestObject + rename = {'attributes_': 'attributes'} + + attributes_ = 42 + + obj = TestObjectFactory.build() + self.assertEqual(42, obj.attributes) + class SubFactoryTestCase(unittest.TestCase): def test_sub_factory(self): @@ -996,11 +1098,13 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 3 class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + model = TestModel2 two = factory.SubFactory(TestModelFactory, one=1) test_model = TestModel2Factory(two__one=4) @@ -1013,10 +1117,12 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + model = TestModel2 two = factory.SubFactory(TestModelFactory, one=factory.Sequence(lambda n: 'x%dx' % n), two=factory.LazyAttribute(lambda o: '%s%s' % (o.one, o.one)), @@ -1033,12 +1139,14 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Sequence(lambda n: int(n)) class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) @@ -1054,7 +1162,8 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject class OtherTestObject(object): @@ -1063,7 +1172,8 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = OtherTestObject + class Meta: + model = OtherTestObject wrapped = factory.SubFactory(TestObjectFactory, two=2, four=4) wrapped__two = 4 @@ -1083,16 +1193,19 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) wrapped_bis = factory.SubFactory(TestObjectFactory, one=1) class OuterWrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject wrap = factory.SubFactory(WrappingTestObjectFactory, wrapped__two=2) @@ -1109,17 +1222,20 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject two = 'two' class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) friend = factory.LazyAttribute(lambda o: o.wrapped.two.four + 1) class OuterWrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject wrap = factory.SubFactory(WrappingTestObjectFactory, wrapped__two=factory.SubFactory(TestObjectFactory, four=4)) @@ -1139,12 +1255,14 @@ class SubFactoryTestCase(unittest.TestCase): # Innermost factory class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject two = 'two' # Intermediary factory class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) wrapped__two = 'three' @@ -1162,11 +1280,13 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject two = 'two' class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) friend = factory.LazyAttribute(lambda o: o.wrapped.two + 1) @@ -1200,20 +1320,24 @@ class SubFactoryTestCase(unittest.TestCase): self.side_b = side_b class InnerMostFactory(factory.Factory): - FACTORY_FOR = InnerMost + class Meta: + model = InnerMost a = 15 b = 20 class SideAFactory(factory.Factory): - FACTORY_FOR = SideA + class Meta: + model = SideA inner_from_a = factory.SubFactory(InnerMostFactory, a=20) class SideBFactory(factory.Factory): - FACTORY_FOR = SideB + class Meta: + model = SideB inner_from_b = factory.SubFactory(InnerMostFactory, b=15) class OuterMostFactory(factory.Factory): - FACTORY_FOR = OuterMost + class Meta: + model = OuterMost foo = 30 side_a = factory.SubFactory(SideAFactory, @@ -1238,12 +1362,14 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 3 two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=False) class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + model = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1261,12 +1387,14 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 3 two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=True) class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + model = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1282,7 +1410,8 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel one = 3 @factory.container_attribute @@ -1292,7 +1421,8 @@ class SubFactoryTestCase(unittest.TestCase): return 42 class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + model = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1310,7 +1440,8 @@ class IteratorTestCase(unittest.TestCase): def test_iterator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Iterator(range(10, 30)) @@ -1323,7 +1454,8 @@ class IteratorTestCase(unittest.TestCase): @tools.disable_warnings def test_iterator_list_comprehension_scope_bleeding(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Iterator([j * 3 for j in range(5)]) @@ -1334,7 +1466,8 @@ class IteratorTestCase(unittest.TestCase): @tools.disable_warnings def test_iterator_list_comprehension_protected(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Iterator([_j * 3 for _j in range(5)]) @@ -1347,7 +1480,8 @@ class IteratorTestCase(unittest.TestCase): def test_iterator_decorator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject @factory.iterator def one(): @@ -1359,6 +1493,38 @@ class IteratorTestCase(unittest.TestCase): for i, obj in enumerate(objs): self.assertEqual(i + 10, obj.one) + def test_iterator_late_loading(self): + """Ensure that Iterator doesn't unroll on class creation. + + This allows, for Django objects, to call: + foo = factory.Iterator(models.MyThingy.objects.all()) + """ + class DBRequest(object): + def __init__(self): + self.ready = False + + def __iter__(self): + if not self.ready: + raise ValueError("Not ready!!") + return iter([1, 2, 3]) + + # calling __iter__() should crash + req1 = DBRequest() + with self.assertRaises(ValueError): + iter(req1) + + req2 = DBRequest() + + class TestObjectFactory(factory.Factory): + class Meta: + model = TestObject + + one = factory.Iterator(req2) + + req2.ready = True + obj = TestObjectFactory() + self.assertEqual(1, obj.one) + class BetterFakeModelManager(object): def __init__(self, keys, instance): @@ -1374,12 +1540,9 @@ class BetterFakeModelManager(object): instance.id = 2 return instance, True - def values_list(self, *args, **kwargs): + def using(self, db): return self - def order_by(self, *args, **kwargs): - return [1] - class BetterFakeModel(object): @classmethod @@ -1397,7 +1560,8 @@ class BetterFakeModel(object): class DjangoModelFactoryTestCase(unittest.TestCase): def test_simple(self): class FakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = FakeModel + class Meta: + model = FakeModel obj = FakeModelFactory(one=1) self.assertEqual(1, obj.one) @@ -1411,8 +1575,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): objects = BetterFakeModelManager({'x': 1}, prev) class MyFakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = MyFakeModel - FACTORY_DJANGO_GET_OR_CREATE = ('x',) + class Meta: + model = MyFakeModel + django_get_or_create = ('x',) x = 1 y = 4 z = 6 @@ -1432,8 +1597,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): objects = BetterFakeModelManager({'x': 1, 'y': 2, 'z': 3}, prev) class MyFakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = MyFakeModel - FACTORY_DJANGO_GET_OR_CREATE = ('x', 'y', 'z') + class Meta: + model = MyFakeModel + django_get_or_create = ('x', 'y', 'z') x = 1 y = 4 z = 6 @@ -1453,8 +1619,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): objects = BetterFakeModelManager({'x': 1}, prev) class MyFakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = MyFakeModel - FACTORY_DJANGO_GET_OR_CREATE = ('x',) + class Meta: + model = MyFakeModel + django_get_or_create = ('x',) x = 1 y = 4 z = 6 @@ -1474,8 +1641,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): objects = BetterFakeModelManager({'x': 1, 'y': 2, 'z': 3}, prev) class MyFakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = MyFakeModel - FACTORY_DJANGO_GET_OR_CREATE = ('x', 'y', 'z') + class Meta: + model = MyFakeModel + django_get_or_create = ('x', 'y', 'z') x = 1 y = 4 z = 6 @@ -1489,37 +1657,40 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_sequence(self): class TestModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel a = factory.Sequence(lambda n: 'foo_%s' % n) o1 = TestModelFactory() o2 = TestModelFactory() - self.assertEqual('foo_2', o1.a) - self.assertEqual('foo_3', o2.a) + self.assertEqual('foo_0', o1.a) + self.assertEqual('foo_1', o2.a) o3 = TestModelFactory.build() o4 = TestModelFactory.build() - self.assertEqual('foo_4', o3.a) - self.assertEqual('foo_5', o4.a) + self.assertEqual('foo_2', o3.a) + self.assertEqual('foo_3', o4.a) def test_no_get_or_create(self): class TestModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = TestModel + class Meta: + model = TestModel a = factory.Sequence(lambda n: 'foo_%s' % n) o = TestModelFactory() self.assertEqual(None, o._defaults) - self.assertEqual('foo_2', o.a) + self.assertEqual('foo_0', o.a) self.assertEqual(2, o.id) def test_get_or_create(self): class TestModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = TestModel - FACTORY_DJANGO_GET_OR_CREATE = ('a', 'b') + class Meta: + model = TestModel + django_get_or_create = ('a', 'b') a = factory.Sequence(lambda n: 'foo_%s' % n) b = 2 @@ -1528,7 +1699,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): o = TestModelFactory() self.assertEqual({'c': 3, 'd': 4}, o._defaults) - self.assertEqual('foo_2', o.a) + self.assertEqual('foo_0', o.a) self.assertEqual(2, o.b) self.assertEqual(3, o.c) self.assertEqual(4, o.d) @@ -1537,8 +1708,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_full_get_or_create(self): """Test a DjangoModelFactory with all fields in get_or_create.""" class TestModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = TestModel - FACTORY_DJANGO_GET_OR_CREATE = ('a', 'b', 'c', 'd') + class Meta: + model = TestModel + django_get_or_create = ('a', 'b', 'c', 'd') a = factory.Sequence(lambda n: 'foo_%s' % n) b = 2 @@ -1547,7 +1719,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): o = TestModelFactory() self.assertEqual({}, o._defaults) - self.assertEqual('foo_2', o.a) + self.assertEqual('foo_0', o.a) self.assertEqual(2, o.b) self.assertEqual(3, o.c) self.assertEqual(4, o.d) @@ -1557,7 +1729,8 @@ class DjangoModelFactoryTestCase(unittest.TestCase): class PostGenerationTestCase(unittest.TestCase): def test_post_generation(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 1 @@ -1575,7 +1748,8 @@ class PostGenerationTestCase(unittest.TestCase): def test_post_generation_hook(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 1 @@ -1596,7 +1770,8 @@ class PostGenerationTestCase(unittest.TestCase): def test_post_generation_extraction(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 1 @@ -1621,7 +1796,8 @@ class PostGenerationTestCase(unittest.TestCase): self.assertEqual(kwargs, {'foo': 13}) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject bar = factory.PostGeneration(my_lambda) @@ -1640,7 +1816,8 @@ class PostGenerationTestCase(unittest.TestCase): self.extra = (args, kwargs) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 3 two = 2 post_call = factory.PostGenerationMethodCall('call', one=1) @@ -1664,15 +1841,17 @@ class PostGenerationTestCase(unittest.TestCase): self.three = obj class TestRelatedObjectFactory(factory.Factory): - FACTORY_FOR = TestRelatedObject + class Meta: + model = TestRelatedObject one = 1 two = factory.LazyAttribute(lambda o: o.one + 1) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 3 two = 2 - three = factory.RelatedFactory(TestRelatedObjectFactory, name='obj') + three = factory.RelatedFactory(TestRelatedObjectFactory, 'obj') obj = TestObjectFactory.build() # Normal fields @@ -1709,12 +1888,14 @@ class PostGenerationTestCase(unittest.TestCase): self.three = obj class TestRelatedObjectFactory(factory.Factory): - FACTORY_FOR = TestRelatedObject + class Meta: + model = TestRelatedObject one = 1 two = factory.LazyAttribute(lambda o: o.one + 1) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 3 two = 2 three = factory.RelatedFactory(TestRelatedObjectFactory) @@ -1743,6 +1924,36 @@ class PostGenerationTestCase(unittest.TestCase): self.assertEqual(3, related.one) self.assertEqual(4, related.two) + def test_related_factory_selfattribute(self): + class TestRelatedObject(object): + def __init__(self, obj=None, one=None, two=None): + obj.related = self + self.one = one + self.two = two + self.three = obj + + class TestRelatedObjectFactory(factory.Factory): + class Meta: + model = TestRelatedObject + one = 1 + two = factory.LazyAttribute(lambda o: o.one + 1) + + class TestObjectFactory(factory.Factory): + class Meta: + model = TestObject + one = 3 + two = 2 + three = factory.RelatedFactory(TestRelatedObjectFactory, 'obj', + two=factory.SelfAttribute('obj.two'), + ) + + obj = TestObjectFactory.build(two=4) + self.assertEqual(3, obj.one) + self.assertEqual(4, obj.two) + self.assertEqual(1, obj.related.one) + self.assertEqual(4, obj.related.two) + + class RelatedFactoryExtractionTestCase(unittest.TestCase): def setUp(self): @@ -1755,10 +1966,12 @@ class RelatedFactoryExtractionTestCase(unittest.TestCase): obj.related = subself class TestRelatedObjectFactory(factory.Factory): - FACTORY_FOR = TestRelatedObject + class Meta: + model = TestRelatedObject class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.RelatedFactory(TestRelatedObjectFactory, 'obj') self.TestRelatedObject = TestRelatedObject @@ -1802,10 +2015,28 @@ class CircularTestCase(unittest.TestCase): self.assertIsNone(b.foo.bar.foo.bar) +class SelfReferentialTests(unittest.TestCase): + def test_no_parent(self): + from .cyclic import self_ref + + obj = self_ref.TreeElementFactory(parent=None) + self.assertIsNone(obj.parent) + + def test_deep(self): + from .cyclic import self_ref + + obj = self_ref.TreeElementFactory(parent__parent__parent__parent=None) + self.assertIsNotNone(obj.parent) + self.assertIsNotNone(obj.parent.parent) + self.assertIsNotNone(obj.parent.parent.parent) + self.assertIsNone(obj.parent.parent.parent.parent) + + class DictTestCase(unittest.TestCase): def test_empty_dict(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Dict({}) o = TestObjectFactory() @@ -1813,7 +2044,8 @@ class DictTestCase(unittest.TestCase): def test_naive_dict(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory() @@ -1821,7 +2053,8 @@ class DictTestCase(unittest.TestCase): def test_sequence_dict(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Dict({'a': factory.Sequence(lambda n: n + 2)}) o1 = TestObjectFactory() @@ -1832,7 +2065,8 @@ class DictTestCase(unittest.TestCase): def test_dict_override(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory(one__a=2) @@ -1840,7 +2074,8 @@ class DictTestCase(unittest.TestCase): def test_dict_extra_key(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory(one__b=2) @@ -1848,7 +2083,8 @@ class DictTestCase(unittest.TestCase): def test_dict_merged_fields(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject two = 13 one = factory.Dict({ 'one': 1, @@ -1861,7 +2097,8 @@ class DictTestCase(unittest.TestCase): def test_nested_dicts(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = 1 two = factory.Dict({ 'one': 3, @@ -1889,7 +2126,8 @@ class DictTestCase(unittest.TestCase): class ListTestCase(unittest.TestCase): def test_empty_list(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.List([]) o = TestObjectFactory() @@ -1897,7 +2135,8 @@ class ListTestCase(unittest.TestCase): def test_naive_list(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.List([1]) o = TestObjectFactory() @@ -1905,7 +2144,8 @@ class ListTestCase(unittest.TestCase): def test_sequence_list(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.List([factory.Sequence(lambda n: n + 2)]) o1 = TestObjectFactory() @@ -1916,7 +2156,8 @@ class ListTestCase(unittest.TestCase): def test_list_override(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.List([1]) o = TestObjectFactory(one__0=2) @@ -1924,7 +2165,8 @@ class ListTestCase(unittest.TestCase): def test_list_extra_key(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject one = factory.List([1]) o = TestObjectFactory(one__1=2) @@ -1932,7 +2174,8 @@ class ListTestCase(unittest.TestCase): def test_list_merged_fields(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject two = 13 one = factory.List([ 1, @@ -1945,7 +2188,9 @@ class ListTestCase(unittest.TestCase): def test_nested_lists(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + model = TestObject + one = 1 two = factory.List([ 3, diff --git a/tests/test_utils.py b/tests/test_utils.py index d321c2a..77598e1 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Copyright (c) 2010 Mark Sandstrom -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 @@ -238,33 +238,33 @@ class ImportObjectTestCase(unittest.TestCase): class LogPPrintTestCase(unittest.TestCase): def test_nothing(self): - txt = utils.log_pprint() + txt = str(utils.log_pprint()) self.assertEqual('', txt) def test_only_args(self): - txt = utils.log_pprint((1, 2, 3)) + txt = str(utils.log_pprint((1, 2, 3))) self.assertEqual('1, 2, 3', txt) def test_only_kwargs(self): - txt = utils.log_pprint(kwargs={'a': 1, 'b': 2}) + txt = str(utils.log_pprint(kwargs={'a': 1, 'b': 2})) self.assertIn(txt, ['a=1, b=2', 'b=2, a=1']) def test_bytes_args(self): - txt = utils.log_pprint((b'\xe1\xe2',)) + txt = str(utils.log_pprint((b'\xe1\xe2',))) expected = "b'\\xe1\\xe2'" if is_python2: expected = expected.lstrip('b') self.assertEqual(expected, txt) def test_text_args(self): - txt = utils.log_pprint(('ŧêßŧ',)) + txt = str(utils.log_pprint(('ŧêßŧ',))) expected = "'ŧêßŧ'" if is_python2: expected = "u'\\u0167\\xea\\xdf\\u0167'" self.assertEqual(expected, txt) def test_bytes_kwargs(self): - txt = utils.log_pprint(kwargs={'x': b'\xe1\xe2', 'y': b'\xe2\xe1'}) + txt = str(utils.log_pprint(kwargs={'x': b'\xe1\xe2', 'y': b'\xe2\xe1'})) expected1 = "x=b'\\xe1\\xe2', y=b'\\xe2\\xe1'" expected2 = "y=b'\\xe2\\xe1', x=b'\\xe1\\xe2'" if is_python2: @@ -273,7 +273,7 @@ class LogPPrintTestCase(unittest.TestCase): self.assertIn(txt, (expected1, expected2)) def test_text_kwargs(self): - txt = utils.log_pprint(kwargs={'x': 'ŧêßŧ', 'y': 'ŧßêŧ'}) + txt = str(utils.log_pprint(kwargs={'x': 'ŧêßŧ', 'y': 'ŧßêŧ'})) expected1 = "x='ŧêßŧ', y='ŧßêŧ'" expected2 = "y='ŧßêŧ', x='ŧêßŧ'" if is_python2: diff --git a/tests/testdata/__init__.py b/tests/testdata/__init__.py index 9956610..b534998 100644 --- a/tests/testdata/__init__.py +++ b/tests/testdata/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 diff --git a/tests/tools.py b/tests/tools.py index 571899b..47f705c 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Copyright (c) 2010 Mark Sandstrom -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 diff --git a/tests/utils.py b/tests/utils.py index 215fc83..7a31ed2 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Copyright (c) 2010 Mark Sandstrom -# Copyright (c) 2011-2013 Raphaël Barrois +# Copyright (c) 2011-2015 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 |