summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/__init__.py8
-rw-r--r--tests/compat.py2
-rw-r--r--tests/cyclic/bar.py2
-rw-r--r--tests/cyclic/foo.py2
-rw-r--r--tests/cyclic/self_ref.py (renamed from tests/test_deprecation.py)34
-rw-r--r--tests/djapp/models.py36
-rw-r--r--tests/djapp/settings.py6
-rw-r--r--tests/test_alchemy.py56
-rw-r--r--tests/test_base.py33
-rw-r--r--tests/test_containers.py2
-rw-r--r--tests/test_declarations.py17
-rw-r--r--tests/test_django.py349
-rw-r--r--tests/test_faker.py135
-rw-r--r--tests/test_fuzzy.py83
-rw-r--r--tests/test_helpers.py2
-rw-r--r--tests/test_mongoengine.py15
-rw-r--r--tests/test_using.py120
-rw-r--r--tests/test_utils.py16
-rw-r--r--tests/testdata/__init__.py2
-rw-r--r--tests/tools.py2
-rw-r--r--tests/utils.py2
21 files changed, 717 insertions, 207 deletions
diff --git a/tests/__init__.py b/tests/__init__.py
index 855beea..b2c772d 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,11 +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_deprecation 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/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 a5e6bf1..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
diff --git a/tests/cyclic/foo.py b/tests/cyclic/foo.py
index 18de362..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
diff --git a/tests/test_deprecation.py b/tests/cyclic/self_ref.py
index a07cbf3..d98b3ab 100644
--- a/tests/test_deprecation.py
+++ b/tests/cyclic/self_ref.py
@@ -1,6 +1,5 @@
# -*- 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
@@ -20,30 +19,19 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-"""Tests for deprecated features."""
-
-import warnings
+"""Helper to test circular factory dependencies."""
import factory
-from .compat import mock, unittest
-from . import tools
-
+class TreeElement(object):
+ def __init__(self, name, parent):
+ self.parent = parent
+ self.name = name
-class DeprecationTests(unittest.TestCase):
- def test_factory_for(self):
- class Foo(object):
- pass
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter('always')
- class FooFactory(factory.Factory):
- FACTORY_FOR = Foo
+class TreeElementFactory(factory.Factory):
+ class Meta:
+ model = TreeElement
- self.assertEqual(1, len(w))
- warning = w[0]
- # Message is indeed related to the current file
- # This is to ensure error messages are readable by end users.
- self.assertIn(warning.filename, __file__)
- self.assertIn('FACTORY_FOR', str(warning.message))
- self.assertIn('model', str(warning.message))
+ 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 9b21181..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
@@ -68,6 +68,15 @@ 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)
@@ -79,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):
@@ -87,3 +97,27 @@ else:
class WithSignals(models.Model):
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 b9222eb..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:
@@ -55,6 +56,16 @@ class StandardFactory(SQLAlchemyModelFactory):
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):
class Meta:
model = models.NonIntegerPk
@@ -88,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.")
@@ -111,22 +143,22 @@ class SQLAlchemyNonIntegerPkTestCase(unittest.TestCase):
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')
@@ -134,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 d1df58e..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
@@ -403,7 +403,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase):
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):
class Meta:
model = TestModel
@@ -414,8 +414,18 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase):
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
- self.assertRaises(base.StubFactory.UnsupportedStrategy, TestModelFactory)
+ 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)
@@ -454,6 +464,23 @@ class FactoryCreationTestCase(unittest.TestCase):
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):
class Meta:
diff --git a/tests/test_containers.py b/tests/test_containers.py
index bd7019e..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
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 41a26cf..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,72 +93,80 @@ def tearDownModule():
django_test_utils.teardown_test_environment()
-class StandardFactory(factory.django.DjangoModelFactory):
- class Meta:
- model = 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)
- foo = factory.Sequence(lambda n: "foo%d" % n)
+ class StandardFactoryWithPKField(factory.django.DjangoModelFactory):
+ class Meta:
+ model = models.StandardModel
+ django_get_or_create = ('pk',)
-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
- foo = factory.Sequence(lambda n: "foo%d" % n)
- pk = None
+ class NonIntegerPkFactory(factory.django.DjangoModelFactory):
+ class Meta:
+ model = models.NonIntegerPk
-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)
- bar = ''
+ class AbstractBaseFactory(factory.django.DjangoModelFactory):
+ class Meta:
+ model = models.AbstractBase
+ abstract = True
-class AbstractBaseFactory(factory.django.DjangoModelFactory):
- class Meta:
- model = models.AbstractBase
- abstract = True
+ foo = factory.Sequence(lambda n: "foo%d" % n)
- foo = factory.Sequence(lambda n: "foo%d" % n)
+ class ConcreteSonFactory(AbstractBaseFactory):
+ class Meta:
+ model = models.ConcreteSon
-class ConcreteSonFactory(AbstractBaseFactory):
- class Meta:
- model = models.ConcreteSon
+ class AbstractSonFactory(AbstractBaseFactory):
+ class Meta:
+ model = models.AbstractSon
-class AbstractSonFactory(AbstractBaseFactory):
- class Meta:
- model = models.AbstractSon
+ class ConcreteGrandSonFactory(AbstractBaseFactory):
+ class Meta:
+ model = models.ConcreteGrandSon
-class ConcreteGrandSonFactory(AbstractBaseFactory):
- class Meta:
- model = models.ConcreteGrandSon
+ class WithFileFactory(factory.django.DjangoModelFactory):
+ class Meta:
+ model = models.WithFile
-class WithFileFactory(factory.django.DjangoModelFactory):
- class Meta:
- model = models.WithFile
+ if django is not None:
+ afile = factory.django.FileField()
- if django is not None:
- afile = factory.django.FileField()
+ class WithImageFactory(factory.django.DjangoModelFactory):
+ class Meta:
+ model = models.WithImage
-class WithImageFactory(factory.django.DjangoModelFactory):
- class Meta:
- model = models.WithImage
+ if django is not None:
+ animage = factory.django.ImageField()
- if django is not None:
- animage = factory.django.ImageField()
+ class WithSignalsFactory(factory.django.DjangoModelFactory):
+ class Meta:
+ model = models.WithSignals
-class WithSignalsFactory(factory.django.DjangoModelFactory):
- class Meta:
- model = models.WithSignals
+
+ class WithCustomManagerFactory(factory.django.DjangoModelFactory):
+ class Meta:
+ model = models.WithCustomManager
+
+ foo = factory.Sequence(lambda n: "foo%d" % n)
@unittest.skipIf(django is None, "Django not installed.")
@@ -174,6 +177,16 @@ class ModelTests(django_test.TestCase):
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.")
class DjangoPkSequenceTestCase(django_test.TestCase):
@@ -183,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)
@@ -221,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')
@@ -295,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.")
@@ -308,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')
@@ -333,8 +346,8 @@ 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.")
@@ -351,6 +364,32 @@ class DjangoAbstractBaseSequenceTestCase(django_test.TestCase):
@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):
@@ -363,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):
@@ -374,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)
@@ -396,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)
@@ -406,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)
@@ -421,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)
@@ -451,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)
@@ -458,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)
@@ -478,6 +557,8 @@ 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)
@@ -491,7 +572,8 @@ class DjangoImageFieldTestCase(unittest.TestCase):
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)
@@ -499,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)
@@ -509,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)
@@ -520,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)
@@ -536,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)
@@ -585,6 +678,19 @@ 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):
@@ -599,6 +705,27 @@ 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):
@@ -641,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 988c179..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
@@ -61,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 f18df4d..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):
@@ -1073,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):
@@ -1475,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):
@@ -1490,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
@@ -1618,14 +1665,14 @@ class DjangoModelFactoryTestCase(unittest.TestCase):
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):
@@ -1636,7 +1683,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase):
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):
@@ -1652,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)
@@ -1672,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)
@@ -1804,7 +1851,7 @@ class PostGenerationTestCase(unittest.TestCase):
model = TestObject
one = 3
two = 2
- three = factory.RelatedFactory(TestRelatedObjectFactory, name='obj')
+ three = factory.RelatedFactory(TestRelatedObjectFactory, 'obj')
obj = TestObjectFactory.build()
# Normal fields
@@ -1877,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):
@@ -1938,6 +2015,23 @@ 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):
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