Giter Club home page Giter Club logo

factory_boy's Introduction

factory_boy

image

image

Latest Version

Supported Python versions

Wheel status

License

factory_boy is a fixtures replacement based on thoughtbot's factory_bot.

As a fixtures replacement tool, it aims to replace static, hard to maintain fixtures with easy-to-use factories for complex objects.

Instead of building an exhaustive test setup with every possible combination of corner cases, factory_boy allows you to use objects customized for the current test, while only declaring the test-specific fields:

class FooTests(unittest.TestCase):

    def test_with_factory_boy(self):
        # We need a 200€, paid order, shipping to australia, for a VIP customer
        order = OrderFactory(
            amount=200,
            status='PAID',
            customer__is_vip=True,
            address__country='AU',
        )
        # Run the tests here

    def test_without_factory_boy(self):
        address = Address(
            street="42 fubar street",
            zipcode="42Z42",
            city="Sydney",
            country="AU",
        )
        customer = Customer(
            first_name="John",
            last_name="Doe",
            phone="+1234",
            email="[email protected]",
            active=True,
            is_vip=True,
            address=address,
        )
        # etc.

factory_boy is designed to work well with various ORMs (Django, MongoDB, SQLAlchemy), and can easily be extended for other libraries.

Its main features include:

  • Straightforward declarative syntax
  • Chaining factory calls while retaining the global context
  • Support for multiple build strategies (saved/unsaved instances, stubbed objects)
  • Multiple factories per class support, including inheritance

Download

PyPI: https://pypi.org/project/factory-boy/

$ pip install factory_boy

Source: https://github.com/FactoryBoy/factory_boy/

$ git clone git://github.com/FactoryBoy/factory_boy/
$ python setup.py install

Usage

Note

This section provides a quick summary of factory_boy features. A more detailed listing is available in the full documentation.

Defining factories

Factories declare a set of attributes used to instantiate a Python object. The class of the object must be defined in the model field of a class Meta: attribute:

import factory
from . import models

class UserFactory(factory.Factory):
    class Meta:
        model = models.User

    first_name = 'John'
    last_name = 'Doe'
    admin = False

# Another, different, factory for the same object
class AdminFactory(factory.Factory):
    class Meta:
        model = models.User

    first_name = 'Admin'
    last_name = 'User'
    admin = True

ORM integration

factory_boy integration with Object Relational Mapping (ORM) tools is provided through specific factory.Factory subclasses:

  • Django, with factory.django.DjangoModelFactory
  • Mogo, with factory.mogo.MogoFactory
  • MongoEngine, with factory.mongoengine.MongoEngineFactory
  • SQLAlchemy, with factory.alchemy.SQLAlchemyModelFactory

More details can be found in the ORM section.

Using factories

factory_boy supports several different instantiation strategies: build, create, and stub:

# Returns a User instance that's not saved
user = UserFactory.build()

# Returns a saved User instance.
# UserFactory must subclass an ORM base class, such as DjangoModelFactory.
user = UserFactory.create()

# Returns a stub object (just a bunch of attributes)
obj = UserFactory.stub()

You can use the Factory class as a shortcut for the default instantiation strategy:

# Same as UserFactory.create()
user = UserFactory()

No matter which strategy is used, it's possible to override the defined attributes by passing keyword arguments:

# Build a User instance and override first_name
>>> user = UserFactory.build(first_name='Joe')
>>> user.first_name
"Joe"

It is also possible to create a bunch of objects in a single call:

>>> users = UserFactory.build_batch(10, first_name="Joe")
>>> len(users)
10
>>> [user.first_name for user in users]
["Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe"]

Realistic, random values

Demos look better with random yet realistic values; and those realistic values can also help discover bugs. For this, factory_boy relies on the excellent faker library:

class RandomUserFactory(factory.Factory):
    class Meta:
        model = models.User

    first_name = factory.Faker('first_name')
    last_name = factory.Faker('last_name')
>>> RandomUserFactory()
<User: Lucy Murray>

Reproducible random values

The use of fully randomized data in tests is quickly a problem for reproducing broken builds. To that purpose, factory_boy provides helpers to handle the random seeds it uses, located in the factory.random module:

import factory.random

def setup_test_environment():
    factory.random.reseed_random('my_awesome_project')
    # Other setup here

Lazy Attributes

Most factory attributes can be added using static values that are evaluated when the factory is defined, but some attributes (such as fields whose value is computed from other elements) will need values assigned each time an instance is generated.

These "lazy" attributes can be added as follows:

class UserFactory(factory.Factory):
    class Meta:
        model = models.User

    first_name = 'Joe'
    last_name = 'Blow'
    email = factory.LazyAttribute(lambda a: '{}.{}@example.com'.format(a.first_name, a.last_name).lower())
    date_joined = factory.LazyFunction(datetime.now)
>>> UserFactory().email
"[email protected]"

Note

LazyAttribute calls the function with the object being constructed as an argument, when LazyFunction does not send any argument.

Sequences

Unique values in a specific format (for example, e-mail addresses) can be generated using sequences. Sequences are defined by using Sequence or the decorator sequence:

class UserFactory(factory.Factory):
    class Meta:
        model = models.User

    email = factory.Sequence(lambda n: 'person{}@example.com'.format(n))

>>> UserFactory().email
'[email protected]'
>>> UserFactory().email
'[email protected]'

Associations

Some objects have a complex field, that should itself be defined from a dedicated factories. This is handled by the SubFactory helper:

class PostFactory(factory.Factory):
    class Meta:
        model = models.Post

    author = factory.SubFactory(UserFactory)

The associated object's strategy will be used:

# Builds and saves a User and a Post
>>> post = PostFactory()
>>> post.id is None  # Post has been 'saved'
False
>>> post.author.id is None  # post.author has been saved
False

# Builds but does not save a User, and then builds but does not save a Post
>>> post = PostFactory.build()
>>> post.id is None
True
>>> post.author.id is None
True

Support Policy

factory_boy supports active Python versions as well as PyPy3.

Debugging factory_boy

Debugging factory_boy can be rather complex due to the long chains of calls. Detailed logging is available through the factory logger.

A helper, factory.debug(), is available to ease debugging:

with factory.debug():
    obj = TestModel2Factory()


import logging
logger = logging.getLogger('factory')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)

This will yield messages similar to those (artificial indentation):

BaseFactory: Preparing tests.test_using.TestModel2Factory(extra={})
  LazyStub: Computing values for tests.test_using.TestModel2Factory(two=<OrderedDeclarationWrapper for <factory.declarations.SubFactory object at 0x1e15610>>)
    SubFactory: Instantiating tests.test_using.TestModelFactory(__containers=(<LazyStub for tests.test_using.TestModel2Factory>,), one=4), create=True
    BaseFactory: Preparing tests.test_using.TestModelFactory(extra={'__containers': (<LazyStub for tests.test_using.TestModel2Factory>,), 'one': 4})
      LazyStub: Computing values for tests.test_using.TestModelFactory(one=4)
      LazyStub: Computed values, got tests.test_using.TestModelFactory(one=4)
    BaseFactory: Generating tests.test_using.TestModelFactory(one=4)
  LazyStub: Computed values, got tests.test_using.TestModel2Factory(two=<tests.test_using.TestModel object at 0x1e15410>)
BaseFactory: Generating tests.test_using.TestModel2Factory(two=<tests.test_using.TestModel object at 0x1e15410>)

Contributing

factory_boy is distributed under the MIT License.

Issues should be opened through GitHub Issues; whenever possible, a pull request should be included. Questions and suggestions are welcome on the mailing-list.

Development dependencies can be installed in a virtualenv with:

$ pip install --editable '.[dev]'

All pull requests should pass the test suite, which can be launched simply with:

$ make testall

In order to test coverage, please use:

$ make coverage

To test with a specific framework version, you may use a tox target:

# list all tox environments
$ tox --listenvs

# run tests inside a specific environment (django/mongoengine/SQLAlchemy are not installed)
$ tox -e py310

# run tests inside a specific environment (django)
$ tox -e py310-djangomain
$ tox -e py310-djangomain-postgres

# run tests inside a specific environment (alchemy)
$ tox -e py310-alchemy
$ tox -e py310-alchemy-postgres

# run tests inside a specific environment (mongoengine)
$ tox -e py310-mongo

Packaging

For users interesting in packaging FactoryBoy into downstream distribution channels (e.g. .deb, .rpm, .ebuild), the following tips might be helpful:

Dependencies

The package's run-time dependencies are listed in setup.cfg. The dependencies useful for building and testing the library are covered by the dev and doc extras.

Moreover, all development / testing tasks are driven through make(1).

Building

In order to run the build steps (currently only for docs), run:

python setup.py egg_info
make doc

Testing

When testing for the active Python environment, run the following:

make test

Note

You must make sure that the factory module is importable, as it is imported from the testing code.

factory_boy's People

Contributors

aledejesus avatar anentropic avatar carljm avatar cclauss avatar demonno avatar dnerdy avatar federicobond avatar francoisfreitag avatar gotgenes avatar gregoiredx avatar jdufresne avatar jeffwidman avatar kamotos avatar kevin-brown avatar kingbuzzman avatar kmike avatar koterpillar avatar last-partizan avatar pfstein avatar rbarrois avatar rrauenza avatar s16h avatar sarahboyce avatar tomleo avatar tsouvarev avatar tyarran avatar vbmendes avatar viicos avatar youssefm avatar zetsub0u avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

factory_boy's Issues

Django Factory_Boy and Pylint

As part of my test suite I run pylint and PEP8 over my code, and when using factory_boy factories, I run into issues with the linting of lines such as:

foo = FooFactory() # Factory for Foo() models, which include a method called 'bar(self)'
foo.field = foo.bar()

Which is flagged as:

E1101: instance of 'FooFactory' has no 'bar' member. 

Is there a way to avoid this other than per line flags telling pylint to ignore E1101 which seems rather inelegant?

factory.Iterator with cycle=False haven't got a option reset

Hi,
I am sorry for my bad english
With the factory.Iterator and cycle=False I can't reset the iterator.
For exemple :

ExempleFactory(factory.DjangoModelFactory):
    id = factory.Iterator([1,2,3], cycle=False)

ExempleFactory.reset(('id',))

ExempleFactory(reset=('id',)

Thanks you

New to factory_boy and needs a little reassurance on testing

Not a bug or anything. I don't know any other places to ask, so here I go:

My first glance tells me factory_boy is awesome. But as I am writing down my unittest for my custom User model, I didn't really know what to test.

  1. Basically, factory_boy builds reusable fixtures that is local to test code (which adds extra doc quality...)
  2. I don't want real database interaction, I will use build instead.
  3. Say I have a User model. If I define a UserFactory, as point 1 above, I would define some dummy values and in my test I might supply UserFactory(username='yeukhon', hashed_pwd='hashed_value').build() and assert attribute hashed_pwd has the value hashed_value?

I guess the confusion is whether doing point 2 actually means testing my models (unittest). In the old days I would mock.patch out the model when I am interacting with them.

Maybe someone can reassure me.

Thanks,

Factory_boy without an ORM

This is more a question than an issue since I didn't find a mailing list where I could ask this question. Apologize if this isn't the place to ask.

I'm trying to use factory_boy without an ORM or Django. I've no experience in either.

So I've got a library in python which is used as a test framework. Over time the test data that was managed using dictionaries has grown in size that it has become unweildy to manage. Much of this test data needs to be passed to my functional tests. So, I decided to use factory_boy for defining this test-data as a representation of factory_boy managed objects.

My object model is similar to the examples shown in factory_boy's wiki page:

AccountFactory (inherit) AdminAccountFactory (inherit) UserAccountFactory

Similarly
NetworkFactory (inherit) IsolatedNetworkFactory (inherit) SharedNetworkFactory and so on...

So my questions are as follows

a) Is factory_boy the right tool for addressing this problem?
b) If yes, can it be used without dependency on Django, Mojo and/or any ORM?
c) If no, what (to your knowledge) would best solve my test management problem?

Thanks in advance,

Get rid of ABSTRACT_FACTORY

is it possible to get rid of the ABSTRACT_FACTORY attribute?

At the moment, not providing a FACTORY_FOR raises the following error, even if the factory itself isn't used outside of its child classes:

AssociatedClassError: Could not determine the class associated with BaseFactory. Use the FACTORY_FOR attribute to specify an associated class.

CircularRelatedFactory as just RelatedFactory

One issue I've come up with is that I need a RelatedFactory that works like CircularSubFactory does: where I can pass in a class name to get a late import. However, rather than adding CircularRelatedFactory, doesn't it make sense to get rid of the idea of a CircularSubFactory and just allow users to pass in either a Class or a string to a class into SubFactory?

The init method could then just check if it's a callable or a string.

Assuming you use a single string to define the class/module (which admittedly maybe isn't backwards compatible) it would be:

class MyFactory
    employee1 = factory.SubFactory('tests.factories.EmployeeFactory')
    employee2 = factory.SubFactory(EmployeeFactory)
    employee3 = factory.RelatedFactory('tests.factories.EmployeeFactory', 'employee')
    employee4 = factory.RelatedFactory(EmployeeFactory, 'employee')

How to debug factories problems

Hi,

i'm trying to use factory boy with some nested factories but i get a PRIMARY KEY error (.. must be unique).

these are my factories

class CategoryParentFactory(factory.Factory):
    FACTORY_FOR = Category
    parent = None
    name = "foo"

class CategoryFactory(factory.Factory):
    FACTORY_FOR = Category
    parent = factory.SubFactory(CategoryParentFactory)
    name = "bar"

class ProductFactory(factory.Factory):
    FACTORY_FOR = Product
    category = factory.SubFactory(CategoryFactory)
    name = "fuz"

if i try something like

cp = CategoryParentFactory.create()
c = CategoryFactory.create()

it works, but

p = ProductFactory.create()

gives me "IntegrityError: PRIMARY KEY must be unique"

How can i debug/understand what happens?

Thanks,

ps: i'm trying to get many products with a single category, so this

p1 = ProductFactory.create(category=c)
p1 = ProductFactory.create(category=c)

gives me the same error

Alessandro

RelatedFactory and custom build strategies

For my model I'm using custom strategies for _build and _create. My _build strategy creates a plain python object which has necessary attributes to make a web server request. The _create strategy makes the actual request and includes additional attributes into the model from the response received. All goes well until I have factories that relate to each other.

I would like to ensure that when a factory X is 'created' then the factory Y (y contains x as RelatedFactory) also gets created. To create X: I do

class X(factory.Factory):
     FACTORY_FOR = EntityX

     EntityY = factory.RelatedFactory(Y)


X.create(webserverConnection)

but webserverConnection isn't passed when the RelatedFactory Y is created. How can I achieve this?

Neo4django support

I am trying to work out how to make factoryboy play nice with neo4django

If I have a simple model defined as so:

from neo4django.db import models

class Country(models.NodeModel):
    code = models.StringProperty(indexed=True)

And then define a factory for the model like so:

import factory
from my.models import Country

class CountryFactory(factory.Factory):
    FACTORY_FOR = Country
    code = 'DE'

CountryFactory.default_strategy = factory.CREATE_STRATEGY

In the very simple example below I get an empty queryset instead of it containing the country I just created.

 import factory
 from .factories import CountryFactory                                                                               
 from my.models import Country

  def test_country():
      c1 = CountryFactory.create()
      pp(c1) # <Country> as expected
      country = Country.objects.all()
      pp(countries) # []

I have spent an afternoon, comparing the example above with the django orm version (which works), tracing each through the debugger to no avail. I was wondering if you would maybe able to point me in the direction of the right bits of code. Happy to supply patches if I get anything working.

Tiny little bug in docs?

I'm just starting, sorry if i'm wrong. In the Subfactory docs:

http://readthedocs.org/docs/factoryboy/en/latest/subfactory.html

The first code example is something similar to this:

# A standard factory
class UserFactory(factory.Factory):
    FACTORY_FOR = User

    # Various fields
    first_name = 'John'
    last_name = factory.Sequence(lambda n: 'D%se' % (o * n))
    email = factory.LazyAttribute(lambda o: '%s.%[email protected]' % (o.first_name.lower(), o.last_name.lower()))

In this piece of code, I don't see o defined anywhere:

    # Where's "o" defined?
    last_name = factory.Sequence(lambda n: 'D%se' % (o * n))

DjangoModelFactory's "_setup_next_sequence" assumes that pk is an integer

Offending code is here:

    @classmethod
    def _setup_next_sequence(cls):
        """Compute the next available PK, based on the 'pk' database field."""

        model = cls._associated_class  # pylint: disable=E1101
        manager = cls._get_manager(model)

        try:
            return 1 + manager.values_list('pk', flat=True
                ).order_by('-pk')[0]
        except IndexError:
            return 1

This problem didn't exist in factory_boy 1.3. My field that was using a non-integer PK is using a sequence, which worked fine previously:

code = factory.Sequence(lambda n: str(n).zfill(3))

I haven't dug into the code enough to know much about the changes that caused this problem, but ultimately I'd like to be able to use the sequence for the field again.

Loading and dumping to and from data

What does everyone think about adding a load/dump API that takes/consumes lists of dictionaries? This would allow for easy consuming and producing JSON / YAML fixtures.

Something like the following.

import factory
from . import models

class UserFactory(factory.Factory):
    FACTORY_FOR = models.User

    first_name = 'John'
    last_name = 'Doe'
    admin = False

# Deserialize an iterable of dictionaries using the factory.
UserFactory.load([{...}, {...}])

# Serialize an iterable of targets to an list of dictionaries
# factoring out attributes provided by factories, etc. 
data = UserFactory.dump([models.User(first_name="Bob"), 
                         models.User()])

assert 'first_name' not in data[1]

Suggestions on UserProfiles

Hi There,

This is for Django. We have a basic User model. When a User object is created a trigger is fired and UserProfile is automatically created.

Ultimately I want to be able to do this:

user = BasicUserFactory(
    username="Foo", userprofile__title="Bar", 
    userprofile__company__name="Co")

How can I create a UserFactory which creates and sets attributes for that new UserProfile? Right now it creates it (but I think this is b/c of the trigger) but I can't seem to set any attributes presumably b/c it already exists.

# models.py
class Company(models.Model):
    name = models.CharField(max_length=32, null=True)

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    company = models.ForeignKey('company.Company', related_name="users")
    title = models.CharField(max_length=32, null=True)
    department = models.CharField(max_length=16, blank=True)

# class User == contrib.auth.models.User

#factories.py
class BaseUserProfileFactory(factory.DjangoModelFactory):
    FACTORY_FOR = UserProfile
    FACTORY_DJANGO_GET_OR_CREATE = ('user', )
    company = factory.SubFactory(
       'apps.company.tests.factories.GeneralOrganizationFactory',
        is_customer=True, name="GeneralCo")
    title = "King of the world.."

class BasicUserFactory(factory.DjangoModelFactory):
    """A base user factory"""
    FACTORY_FOR = User
    FACTORY_DJANGO_GET_OR_CREATE = ('username', )
    username = factory.Sequence(lambda n: 'user_{0}'.format(n))
    first_name = factory.Sequence(lambda n: 'first_{0}'.format(n))
    last_name = factory.Sequence(lambda n: 'last_{0}'.format(n))
    email = factory.Sequence(lambda n: 'user_{0}@home.com'.format(n))
    is_active = True
    is_staff = False
    is_superuser = False
    password = factory.PostGenerationMethodCall('set_password', 'password')

    userprofile = factory.RelatedFactory(
BaseUserProfileFactory, 'user', )

RelatedFactory created even when passing None kwargs

There is no way to avoid the creation of an object via RelatedFactory even when this related param is set to None via kwargs in factory instantiation. Example:

** Factory file **

MyFactory(factory.DjangoModelFactory):
param1 = factory.RelatedFactory('model_file.MyModel')

** Test file **

obj = MyFactory(param1=None) # param1 exists in db

Regards,

Mixing factories and fixtures: how to set as attribute a model fetch from the database

I'm having fun using factories, but there are some "initial" - "always the same" - "needed by the app" data that i load with fixtures (and it's not so funny to recreate this with factories).

Now, what i want to achieve is this:

class FooFactory(factory.Factory):
    FACTORY_FOR = Foo
    bar = Bar.objects.get(id=1)

i have tried but i get this error executing the test
django.db.utils.DatabaseError: no such table: bar

I presume that it happens because the factories import execute before the database creation.

Any hint? Can i use the LazyAttribute in some way?

Thanks

PS. I ask here because i don't think there is a dedicated google groups, right?

Performing methods on SelfAttribute should be possible.

Hi there,

Oh factory_boy where have you been all of my life. This thing is AWESOME!!

I can't figure out how to perform an action on a SelfAttribute. I want to transform it a bit..

class RaterUserFactory(NonCompanyProfile):
    """A factory for a rater user"""
    FACTORY_FOR = UserProfile
    FACTORY_DJANGO_GET_OR_CREATE = ('user', )
    user = factory.SubFactory(BaseUserNoProfileFactory, username="rater")
    company = factory.SubFactory('apps.company.tests.RaterOrganizationFactory', is_customer=True,
                                 name=factory.SelfAttribute('..user.username').capitalize() + "Co")```

PostGeneration passes invalid kwargs in lambda

This is example from documentation

class MyFactory(factory.Factory):
    blah = factory.PostGeneration(lambda obj, create, extracted, **kwargs: 42)

MyFactory(
    blah=42,  # Passed in the 'extracted' argument of the lambda
    blah__foo=1,  # Passed in kwargs as 'foo': 1
    blah__baz=2,  # Passed in kwargs as 'baz': 2
    blah_bar=3,  # Not passed
)

But in real, 'foo' and 'baz' will not occurs in kwargs dictionary when blah argument is set.

In my tests:

MyFactory(blah=42,  blah__foo=1) # results in extracted=42 and kwargs={}
MyFactory(blah__foo=1) # results in extracted=None and kwargs={'foo'}

tested on latest master

Confusion over README vs. Readthedocs

The README says that I should use a LazyAttribute(lambda o: OtherFactory()) in order to have a "SubFactory" on one of my factories.

Readthedocs, however actually has a chapter about factory.SubFactory AND it has a chapter about factory.RelatedFactory

I am confused. Let's say I have a UserFactory and a UserProfileFactory (very commong for Django projects, I guess)... which of the three documented approaches would be the correct one?

How to get dict dump of Factory

Hello,

I need to get a full dump of a Factory as a dict so that I can serialize it to json. FactoryName.attributes() works great except when there is a SubField, in which case it evaluates it and returns an instantiated version of the object as opposed to a dictionary of key: value of the SubField attributes.

I tried to hack around this by traversing the Factory myself but it turns out that I'll have to duplicate a lot of code that already exists. Do you see an easy way to do this?

Comparisons using .build() creates unexpected behavior

When using .build() to create an instance of a model (in this case, using Django), the resulting objects, even if attributes are different, compare as the same.

Example:

object1 = PersonFactory.build(name="Bob")
object2 = PersonFactory.build(name="Joe")
if object1 == object2:
    print "Oops."

If I create the objects, the comparison fails. If I build them (without hitting the DB), the comparison resolves as True.

Fuzzy attribute generation

During unit testing, it's often desirable to test with randomized values as opposed to hard-coded values, see Fuzzy Testing. While it's easy enough to add randomization with the random package, the problem is that evaluation of the randomized result is performed once at the class level. We would like to have randomization performed for each object created.

I cannot import factory.django.DjangoModelFactory

No matter how I try it. I can't seem to get a reference to DjangoModelFactory.

I tried the following like the tests do.

import factory.django

# or inheriting from 

factory.django.DjangoModelFactory

It keeps complaining about not being able to find django.

SQLAlchemy model primary key column attribute name must match column name

So we've got a set of SQLAlchemy models like so (don't ask why, it makes me sad).

class Test(Base):
    __tablename__ = "test"

    id = sqlalchemy.Column('id_', sqlalchemy.Integer, primary_key=True)

When using a factory for the class we get:

Traceback (most recent call last):
  File "<pyshell#0>", line 16, in <module>
    TestFactory.build()
  File "/usr/local/lib/python2.7/dist-packages/factory/base.py", line 434, in build
    attrs = cls.attributes(create=False, extra=kwargs)
  File "/usr/local/lib/python2.7/dist-packages/factory/base.py", line 316, in attributes
    force_sequence=force_sequence,
  File "/usr/local/lib/python2.7/dist-packages/factory/containers.py", line 263, in build
    sequence = self.factory._generate_next_sequence()
  File "/usr/local/lib/python2.7/dist-packages/factory/base.py", line 287, in _generate_next_sequence
    cls._next_sequence = cls._setup_next_sequence()
  File "/usr/local/lib/python2.7/dist-packages/factory/alchemy.py", line 37, in _setup_next_sequence
    pk = getattr(model, model.__mapper__.primary_key[0].name)
AttributeError: type object 'Test' has no attribute 'id_'

A full example:

from sqlalchemy.ext.declarative import declarative_base
import sqlalchemy
import factory.alchemy

Base = declarative_base()

class Test(Base):
    __tablename__ = "test"

    id = sqlalchemy.Column('id_', sqlalchemy.Integer, primary_key=True)

class TestFactory(factory.alchemy.SQLAlchemyModelFactory):
    FACTORY_FOR = Test
    FACTORY_SESSION = None

TestFactory.build()

FactoryBoy creates a new object from SubFactory despite FACTORY_DJANGO_GET_OR_CREATE

I am using the setting FACTORY_DJANGO_GET_OR_CREATE. But in some cases, when I ask for an existing object with an existing SubFactory object, it creates an unused object despite this setting.

For example, in a brand new project, I typed:

# models.py
from django.db import models

class A(models.Model):
    name = models.CharField(max_length=10)

class B(models.Model):
    name = models.CharField(max_length=10)
    a = models.ForeignKey(A)

And

# factories.py
import factory

from . import models

class AFactory(factory.DjangoModelFactory):
    FACTORY_FOR = models.A
    FACTORY_DJANGO_GET_OR_CREATE = ('name',)

    name = factory.Sequence(lambda n: 'A-{0}'.format(n))

class BFactory(factory.DjangoModelFactory):
    FACTORY_FOR = models.B
    FACTORY_DJANGO_GET_OR_CREATE = ('name',)

    name = factory.Sequence(lambda n: 'B-{0}'.format(n))
    a = factory.SubFactory(AFactory)

Then:

from factories import *

a = AFactory(name="Apple")
models.A.objects.all()
# one object
b = BFactory(a__name="Apple", name="Beetle")
models.B.objects.all()
models.A.objects.all()
# one A object, one B object
b = BFactory(name="Beetle")
models.B.objects.all()
models.A.objects.all()
# still one B object, but now a new, unused A object too

The final call to BFactory has brought into being a new object of class A, even though the B object with name Beetle already exists (and is not re-created). Why, and how do I stop this new A object being created?

(I know I can get around this by calling instead:

b = BFactory(name="Beetle", a__name="Apple")

but in my actual use case, I have several dependencies and levels of hierarchy, and it's messy to supply extra redundant parameters this way - and I can't seem to get the right combination of parameters.)

Thanks!

(I also asked this on StackOverflow here too.)

Subfactory for M2M fields?

We have a model which has a M2M relation to the user model. So in our factory we do this:

@classmethod
def _prepare(cls, create, **kwargs):
    obj = super(TaskFactory, cls)._prepare(create, **kwargs)
    if create:
        obj.users.add(UserFactory())
    return obj

It's a bit annoying to do this. Wouldn't it be sexy if we could do something like this:

class MyFactory(factory.Factory):
    ...
    users = factory.M2MSubfactory(UserFactory, 2)

So that would mean: Please add two users. Do you think this would be possible? Would it be a difficult change? Does it make sense at all?

DjangoModelFactory doesn't support raw loading

factory_boy can be used to replace django fixtures.

Fixtures

  • create model instances using instance.save_base(raw=True, **kwargs). raw=True is passed to post_save handlers
  • load data for parent and child model separately in case of multi-table inheritance (MTI)

DjangoModelFactory

  • creates models instances using models manager's create method. post_save handlers are invoked with raw=False
  • calls child save method in case of MTI, no need to save parent model separately

Issue objective

  • support raw kwarg for DjangoModelFactory.create: MyModelDjangoFactory.create(raw=True, **kwargs). When raw is True create method calls save_base instance method
  • handle MTI case and call save_base for all models from hierarchy for given model

loaddata with factory_boy

Could you explain what is the best practice to use factory boy to load initial data to a development database ?

Question regarding nested sub-factories

Suppose the following setup:

class RegionFactory(Factory):
    pass

class BuildingFactory(Factory):
    region = SubFactory(RegionFactory)

class PersonFactory(Factory):
   region = SubFactory(RegionFactory)

class RoomFactory(Factory):
   building = SubFactory(BuildingFactory)
   person = SubFactory(PersonFactory)

If I were to construct a RoomFactory, this would result in two RegionFactorys being created (room.building.region, room.person.region).

What I've thus far been doing to solve this problem is the following:

region = RegionFactory()
room = RoomFactory(
    building__region=region,
    person__region=region,
)

This is a common pattern. Is there anyway to accomplish this within a factory definition, so I do not have to repeat this pattern?

Thank you!

LazyAttribute should have access to the build strategy

I'm using LazyAttribute to check if a foreign key exists and return it or else create it. Currently there isn't a way in that function to know the build strategy so it can know if it should build or create the model it is returning.

create() method doesn't save model

I have factory

import factory
class GroupFactory(factory.Factory):
    FACTORY_FOR = Group    
    remote_id = factory.Sequence(lambda n: n)

Method create doesn't save model, I should call it especially:

In [1]: from vkontakte_groups.factories import GroupFactory    
In [2]: group = GroupFactory.create()    
In [3]: group.id, group.pk
Out[3]: (None, None)    

In [4]: group.save()    
In [5]: group.id, group.pk
Out[5]: (890, 890)    

In [6]: import factory    
In [7]: factory.__version__
Out[7]: '2.1.0-dev'

That is very strange. Before it was behaviour with saving by default and I don't know what was changed.. Should I post here more environment settings?

factory.Sequence doesn't work with DjangoModelFactory

Factory Boy 2.0.0

Given the following class:

class TagFactory(factory.DjangoModelFactory):
    FACTORY_FOR = Tag

    name = factory.Sequence(lambda n: 'tag_{}'.format(n))

all Tag objects have the same name. It works fine with factory.Factory

PostGenerationMethodCall problem when calling super(...).__init__(..)

I have the following:

from factory import Factory
from factory.declarations import PostGenerationMethodCall
from django.contrib.auth.models import User

class UserFactory(Factory):
    FACTORY_FOR = User

    username = 'john'
    first_name = 'John'
    last_name = 'Doe'
    email = '[email protected]'

    password = PostGenerationMethodCall('set_password', password='123456')

and when only importing the file where that code is, I'm getting:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\django-project\tests\__init__.py", line 15, in <module>
    class UserFactory(factory.Factory):
  File "C:\django-project\tests\__init__.py", line 25, in UserFactory
    method_args='123456')
  File "C:\Python27\lib\site-packages\factory\declarations.py", line 356, in __init__
    super(RelatedFactory, self).__init__(extract_prefix)
TypeError: super(type, obj): obj must be an instance or subtype of type

I was reading the documentation, and I found the PostGenerationMethodCall, which is exactly what I need, but I couldn't find that piece of code when installing factory_boy using pip install factory_boy, so I got the code directly from the repo.

Example for Django FileField and ImageField values

When creating a factory for a model that has a FileField or ImageField, it would be nice to have some helper factories.

My current solution is this:

import StringIO

import factory
from PIL import Image

from django.core.files.uploadedfile import InMemoryUploadedFile

from apps.photos.models import Photo


def django_image(name, size=200, color='red'):
    thumb = Image.new('RGB', (size, size,), color)
    thumb_io = StringIO.StringIO()
    thumb.save(thumb_io, format='JPEG')
    thumb_io.seek(0)
    return InMemoryUploadedFile(thumb_io, None, name, 'image/jpeg', thumb_io.len, None)


class PhotoFactory(factory.DjangoModelFactory):
    FACTORY_FOR = Photo

    @factory.post_generation
    def image(self, create, extracted, **kwargs):
        if extracted:
            image_name, image = extracted
        else:
            image_name = 'image.jpg'
            image =django_image(image_name, **kwargs)
        self.image.save(image_name, image)

Allow DjangoModelFactories to use 'app.Model'.

As moved over from dnerdy/factory_boy#9

@rbarrois said

By the way, I'm strongly against the proposed behavior:

  • Django's way could change in the future, and requires a single model for each app
  • factory_boy aims to handle more situations, ORMs and frameworks than just Django, and should keep a consistent behavior across all projects.

The convention of identifying model instances by app.ModelName is certainly not going anywhere in Django at present - I'm quite familiar with the app-refactor branch and this does not attempt to change this convention at all. As an example, consider the recently introduced AUTH_USER_MODEL setting which follows this convention.

I understand that factory_boy aims to support multiple ORMs etc, which is why the patch on the other project is applied only to DjangoModelFactory, which is already Django specific.

My main reason for doing this is that my factories.py have a large number of factories defined in them, and I generally do not require the model class for anything other than setting FACTORY_FOR - it results in a lot of imports to the file which aren't really needed.

If you are willing to reconsider your opposition to the proposed behaviour, then I can upgrade the patch apporpriately.

Info about supported Django versions

I have problem with upgrade from 1.3 to 2.1.1. This may be caused by my Django version (1.4.5). You should document what Django versions are supported.

Provide a way to create OneToOne models from "the other side"

It seems there is no easy way to create a User and a Profile using UserFactory (not the ProfileFactory) with factory_boy now. Creating User with Profile factory is not always a solution because there can be several profiles, and it is overall not nice to create main model through one of the side models with extra info.

What I've tried:

class ProfileFactory(DjangoModelFactory):
    FACTORY_FOR = Profile
    gender = 'F'

#   @factory.container_attribute
#   def user(self, cont):           
#      return cont[0]

#   @factory.container_attribute
#   def user_id(self, cont):           
#      return cont[0].id


class UserFactory(DjangoModelFactory):
    FACTORY_FOR = User        
    profile = SubFactory(ProfileFactory)

It is possible to use _prepare method to create the profile but this way 'profile__gender' kwarg won't work (and it is not easier than writing creation function without factory-boy).

Are there better ways to solve this problem or is it better to dig into sources and try to craft a pull request?

Add support for dict/list/tuple attributes

See https://gist.github.com/3002546 :

This should work:

class MyFactory(factory.Factory):
  foo = {
    'a': factory.InfiniteIterator([1, 2, 3]),
  }

A good implementation would be:

class MyFactory(factory.Factory):
  foo = factory.DictFactory(a=factory.InfiniteIterator([1, 2, 3]))

  bar = factory.DictFactory({
    'a': factory.InfiniteIterator([1, 2, 3]),
  })

Sequence increments by 2 for attributes in SubFactories

Using for the most part the example code in RTD:

import factory
import random

#
# Object Classes
#
class Account(object):
    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __str__(self):
        return '%s (%s)' % (self.username, self.email)


class Profile(object):

    GENDER_MALE = 'm'
    GENDER_FEMALE = 'f'
    GENDER_UNKNOWN = 'u'  # If the user refused to give it

    def __init__(self, account, gender, firstname, lastname, planet='Earth'):
        self.account = account
        self.gender = gender
        self.firstname = firstname
        self.lastname = lastname
        self.planet = planet

    def __unicode__(self):
        return u'%s %s (%s)' % (
            unicode(self.firstname),
            unicode(self.lastname),
            unicode(self.account.username),
        )


#
# Factories
#
class AccountFactory(factory.Factory):
    FACTORY_FOR = Account

    username = factory.Sequence(lambda n: 'john%s' % n)
    email = factory.LazyAttribute(lambda o: '%[email protected]' % o.username)


class ProfileFactory(factory.Factory):
    FACTORY_FOR = Profile

    account = factory.SubFactory(AccountFactory)
    gender = random.choice([Profile.GENDER_MALE, Profile.GENDER_FEMALE])
    firstname = u'John'
    lastname = u'Doe'

if __name__ == '__main__':
    accounts1 = [AccountFactory.build() for n in range(10)]
    profiles = [ProfileFactory.build() for n in range(10)]
    accounts2 = [AccountFactory.build() for n in range(10)]

    print 'Directly created Accounts through AccountFactory:'
    print '\n'.join([a.username for a in accounts1])
    print '\nIndirectly created Accounts through SubFactory within ProfileFactory:'
    print '\n'.join([p.account.username for p in profiles])
    print '\nMore directly created Accounts through AccountFactory:'
    print '\n'.join([a.username for a in accounts2])

Notice in __unicode__ method of Profile, self.account.accountname had to be changed to self.account.username.

When running the above, the output is:

Directly created Accounts through AccountFactory:
john0
john1
john2
john3
john4
john5
john6
john7
john8
john9

Indirectly created Accounts through SubFactory within ProfileFactory:
john10
john12
john14
john16
john18
john20
john22
john24
john26
john28

More directly created Accounts through AccountFactory:
john30
john31
john32
john33
john34
john35
john36
john37
john38
john39

Just looked at it quickly, but seems to be an issue with multiple calls of _generate_next_sequence within class hierarchy.

RelatedFactory parametrs

Hi there,

I took this example RelatedFactory and modified it with the "name" field.

Here is my source code:

# models.py
class User(models.Model):
    pass

class UserLog(models.Model):
    user = models.ForeignKey(User)
    name = models.CharField()
    action = models.CharField()


# factories.py
class UserFactory(factory.DjangoModelFactory):
    FACTORY_FOR = models.User

    log = factory.RelatedFactory(UserLogFactory, 'user', name='test', action='create')

This caused the following error:

TypeError: __init__() got multiple values for keyword argument 'name'

Add related models on Save

I have a ContactListFactory and a ContactFactory. Each ContactFactory has a related contact_list:

class ContactListFactory(factory.Factory):
    FACTORY_FOR = ContactList

    name = factory.LazyAttributeSequence(lambda _, n: 'Contact List {}'.format(n))


class ContactFactory(factory.Factory):
    FACTORY_FOR = Contact

    email = factory.LazyAttributeSequence(lambda _, n: '{}@example.com'.format(n))
    contact_list = factory.SubFactory(ContactListFactory)

Is it possible that when I create a ContactListFactory, to auto-create a Contact factory that has that list as it's contact_list?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.