Code Monkey home page Code Monkey logo

pytest-factoryboy's People

Contributors

alessio-b2c2 avatar asfaltboy avatar asottile avatar bluetech avatar blueyed avatar bubenkoff avatar carljm avatar dduong42 avatar gergelykalmar avatar graingert avatar hoefling avatar hugovk avatar jpic avatar kianmeng avatar mouchimotte avatar olegpidsadnyi avatar p13773 avatar phankiewicz avatar pre-commit-ci[bot] avatar prmtl avatar skarzi avatar stranger6667 avatar toshitanian avatar youtux 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

pytest-factoryboy's Issues

Test star imports in conftest.py

Hi all,

When you have a project with many apps and many factories, you may not want to import them all explicitely in the conftest.py. So you import them with a star per package. (in general not a good practice)

IMHO, it would be great if pytest-factoryboy could emit an error for clashing names, rather than silently ignoring/overwriting them.

Thanks for the great work else!

AttributeError: 'PytestPluginManager' object has no attribute 'addhooks'

'addhooks' attribute of PytestPluginManager is removed at pytest 5.0.0.

Because of this, add_hookspecs = getattr(pluginmanager, 'add_hookspecs', pluginmanager.addhooks) does not work (#16). It occur following error.

Traceback (most recent call last):
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/bin/pytest", line 10, in <module>
    sys.exit(main())
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/_pytest/config/__init__.py", line 55, in main
    config = _prepareconfig(args, plugins)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/_pytest/config/__init__.py", line 200, in _prepareconfig
    pluginmanager=pluginmanager, args=args
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/hooks.py", line 289, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/manager.py", line 87, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/manager.py", line 81, in <lambda>
    firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/callers.py", line 203, in _multicall
    gen.send(outcome)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/_pytest/helpconfig.py", line 89, in pytest_cmdline_parse
    config = outcome.get_result()
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/_pytest/config/__init__.py", line 661, in pytest_cmdline_parse
    self.parse(args)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/_pytest/config/__init__.py", line 869, in parse
    self._preparse(args, addopts=addopts)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/_pytest/config/__init__.py", line 815, in _preparse
    self.pluginmanager.load_setuptools_entrypoints("pytest11")
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/manager.py", line 293, in load_setuptools_entrypoints
    self.register(plugin, name=ep.name)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/_pytest/config/__init__.py", line 302, in register
    ret = super().register(plugin, name)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/manager.py", line 121, in register
    hook._maybe_apply_history(hookimpl)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/hooks.py", line 336, in _maybe_apply_history
    res = self._hookexec(self, [method], kwargs)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/manager.py", line 87, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/manager.py", line 81, in <lambda>
    firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/callers.py", line 208, in _multicall
    return outcome.get_result()
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "/Users/ohing/.virtualenvs/django-drf-project-template-Kk8KycnX/lib/python3.7/site-packages/pytest_factoryboy/plugin.py", line 117, in pytest_addhooks
    add_hookspecs = getattr(pluginmanager, 'add_hookspecs',  pluginmanager.addhooks)
AttributeError: 'PytestPluginManager' object has no attribute 'addhooks'

List declaration raises fixture 'list' not found

factory_boy List declarations are not working with pytest_factoryboy for me. Below is a simple example that should bring out the issue (and an attachment). Could I please get any feedback on this?

Thanks in advance
list_declaration_example.py.zip

import factory
from pytest_factoryboy import register


class ClassA(object):
    def __init__(self):
        self._val = 'test_value'

    @property
    def val(self):
        return self._val


class ClassB(object):
    def __init__(self):
        self._arr = [ClassA()]

    @property
    def arr(self):
        return self._arr


class ClassAFactory(factory.Factory):
    """TestClassA factory."""
    class Meta:
        model = ClassA

    _val = 'test_value'


class ClassBFactory(factory.Factory):
    """TestClassB factory."""
    class Meta:
        model = ClassB

    arr = factory.List([
        factory.SubFactory(ClassAFactory)
    ])

register(ClassAFactory)
register(ClassBFactory)

def test_example_a(class_a):
    """
    Assert that the nested list is properly tested
    """
    assert class_a.val == 'test_value'

def test_example_b(class_b):
    """
    Assert that the nested list is properly tested
    """
    assert len(class_b.arr) == 1

============================= test session starts ==============================
platform darwin -- Python 3.5.2, pytest-3.3.2, py-1.5.2, pluggy-0.6.0
rootdir: /Users/alejandrosanchez/Development/testdir, inifile: setup.cfg
plugins: factoryboy-2.0.1, cov-2.5.1
collected 2 items
list_declaration_example.py .E                                           [100%]
test setup failed
file /Users/alejandrosanchez/Development/testdir/list_declaration_example.py, line 49
  def test_example_b(class_b):
file <string>, line 2: source code not available
file <string>, line 2: source code not available
E       fixture 'list' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, class_a, class_a_factory, class_b, class_b__arr, class_b_factory, cov, doctest_namespace, factoryboy_request, monkeypatch, pytestconfig, record_xml_property, recwarn, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

<string>:2


==================================== ERRORS ====================================
_______________________ ERROR at setup of test_example_b _______________________
file /Users/alejandrosanchez/Development/testdir/list_declaration_example.py, line 49
  def test_example_b(class_b):
file <string>, line 2: source code not available
file <string>, line 2: source code not available
E       fixture 'list' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, class_a, class_a_factory, class_b, class_b__arr, class_b_factory, cov, doctest_namespace, factoryboy_request, monkeypatch, pytestconfig, record_xml_property, recwarn, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

<string>:2
====================== 1 passed, 1 error in 0.10 seconds =======================
Process finished with exit code 0

Factory.build fixtures

Might be worth adding fixtures for creating models with build instead of create

I know this exists because I've used FactoryBot in Rails and I knew to look for it, but others might not, and it's probably worth nudging people towards writing non-db tests when they can

If I've understood correctly, currently the only way to build is to use the factory fixture and call build?

def test(asset_factory):
    asset = asset_factory.build()

Automatically registering fixtures like asset_build or similar might be a way to go. Thoughts?

Can't use SubFactory with dict as model

I'm not sure if this is currently supported or not, but I'm not actually trying to work with objects. I'd like to use factoryboy to just generate dicts for test data:

test.py:

import factory
import pytest_factoryboy


class ChildFactory(factory.Factory):
    class Meta:
        model = dict

    child_attr = 'default'


class ParentFactory(factory.Factory):
    class Meta:
        model = dict

    child = factory.SubFactory(ChildFactory)


pytest_factoryboy.register(ParentFactory, 'parent')


def test_basic(parent):
    assert parent.child.child_attr == 'default'

Test output:

$ pytest test.py
========================================================================================================================================================================== test session starts ===========================================================================================================================================================================
platform linux2 -- Python 2.7.6, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
rootdir: /tmp, inifile:
plugins: factoryboy-1.3.1
collected 1 items

test.py E

================================================================================================================================================================================= ERRORS =================================================================================================================================================================================
______________________________________________________________________________________________________________________________________________________________________ ERROR at setup of test_basic ______________________________________________________________________________________________________________________________________________________________________
file /tmp/test.py, line 22
  def test_basic(parent):
file <string>, line 2: source code not available
file <string>, line 2: source code not available
E       fixture 'dict__child_attr' not found
>       available fixtures: cache, capfd, capsys, doctest_namespace, factoryboy_request, monkeypatch, parent, parent__child, parent_factory, pytestconfig, record_xml_property, recwarn, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

<string>:2
======================================================================================================================================================================== 1 error in 0.02 seconds =========================================================================================================================================================================

Output of pip freeze:

factory-boy==2.8.1
Faker==0.7.17
inflection==0.3.1
ipaddress==1.0.18
py==1.4.34
pytest==3.1.2
pytest-factoryboy==1.3.1
python-dateutil==2.6.0
six==1.10.0

If this shouldn't be supported in the plugin, I'd be happy to use some other workaround that pokes through factoryboy/pytest_factoryboy internals.

Duplicate Subfactory not working, reusing existing object

I'm using Django and have a Model with multiple ForeginKey pointing to the same Model. I have factories created like:

 class FooFactory(DjangoModelFactory):
     class Meta:
         model = Foo
     value = factory.fuzzy.FuzzyInteger(100)
     active = False
 
 class BarFactory(DjangoModelFactory):
     class Meta:
         model = Bar
     a = factory.SubFactory(FooFactory, active=True)
     b = factory.SubFactory(FooFactory, active=False)
     c = factory.SubFactory(FooFactory)

register(FooFactory, "foo")
register(BarFactory, "bar")

When I call BarFactory in test it creates object having different objects having different values. But when i get it by fixture it returns all fields having the same model attached ignoring additional flags.

So far I have made a workaround assigning a, b and c in BarFactory _create() method, but in that way i loose all benefits of this plugin.

py.text --fixture produces unorderable types: module() < str()

In conftest.py I am registering factory classes from the django ORM factoryboy base class

I am importing register by
"from pytest_factoryboy import register" [I have found that it matters]

This issue occurs on either of the two below as the factory class:
factory.Factory or factory.djangoORM...Factory (sorry can't remember)

To produce error:
Running the command
"py.test --fixtures DIRECTORY"
where DIRECTORY is folder containing pytest.ini & manage.py

That command lists the fixtures available for the test configuration.

That command produces: "unorderable types: module() < str()"

I traced it back through and by modifying
pytest_factorboy\fixture.py

in the make_fixture function where it was
fixture_func.module = module
I changed it to
fixture_func.module = str(module)

and all the fixtures were listed properly, but the fixtures I registered through pytest_factoryboy had the fixture module grouping in "c:\folder\folder\conftest.py"

I then changed it to
fixture_func.module = os.path.basename(module.path[0])

or sorry something like it, but gave it the base filename of conftest
fixture_func.module = "conftest"

and the fixtures were grouped in the correct location with py.test --fixtures

Django is amazing
factoryboy is great
py.test is wonderful
&
pytest_factoryboy is a must have! Thank you all for the work you do!

Successfully just had world class Test Driven Development today with what I consider good tests. Implementing your library was a very good call....

Impossible to override create param for model fixture

Hi guys. Thanks for the work you've done. I use this project quite often and there is a little problem.

It's possible to pass in create=True param to register function to override default behavior of a factory fixture.

Unfortunately it does not affect a model fixture and it's impossible to override this behavior. Quite often my tests need in-db model instance. Right now I need to do:

def test_my_test(some_obj):
     some_obj.save()
     ...

This is a little be annoying and to me eliminates the benefit of that fixture. Because I can achieve the same goal with:

def test_my_tests(some_obj_factory):
     some_obj = some_obj_factory() 

It would very convenient to be able not to call save each time before the test.

It is very strange why object is not saved in DB.

Multi-Table Inheritance

Multi-Table Inheritance is presenting some challenges with pytest-factoryboy

We currently have one-to-one's for some models so a lot of our tests are based on this concept:

def test_assets(db, asset, photo):
    assert asset == photo.asset

But now we're switching to MTI where the Photo model is a subtype of Asset and thus our PhotoFactory inherits from AssetFactory

This means the asset and photo fixtures generate independent asset records – photo.asset is still an Asset but that is now a "parent record" and is not assignable afaik

@olegpidsadnyi It would be good if the above test could still pass, but I am not sure how to achieve this, I've tried throwing more LazyFixture('asset') in but that doesn't seem to help – any guidance?

Subfactory does not work with self-referencing ForeignKey relationships

It seems to be that SubFactory does not work with self-referencing ForeignKey relationships. I have a model with a foreign key to self:

class MyAuthor(Model):
    full_name = CharField('Full name', max_length=255)
    original_author = ForeignKey('self', null=True)

This is the factory I tried to use:

class MyAuthorFactory(factory.django.DjangoModelFactory):
    full_name = 'John Doe'
    original_author = factory.SubFactory('app.factories.MyAuthorFactory')

    class Meta:
        model = 'app.models.Author'

I registered the factory like this:

register(MyAuthorFactory, 'myauthor')

And got this error:

recursive dependency involving fixture 'myauthor' detected
available fixtures: ... myauthor, myauthor__full_name, ...

DeprecationWarning: use of getfuncargvalue is deprecated, use getfixturevalue

With pytest 3.8 using pytest-factoryboy starts producing

/.../python3.6/site-packages/pytest_factoryboy/plugin.py:107: DeprecationWarning: getfuncargvalue is deprecated, use getfixturevalue
  factoryboy_request = request.getfuncargvalue("factoryboy_request")

Here (https://docs.pytest.org/en/latest/warnings.html#deprecationwarning-and-pendingdeprecationwarning) is chagne in pytest that make this issue visible again, but its till there.

This is similar/same issue as #41 . Even after rewrite latest pytest-factoryboy still uses getfuncargvalue in pytest_factoryboy/plugin.py lines 73 and 107.

If this is not intentional can prepare PR to fix this.

ManyToMany PostGeneration class

Most m2m relation handling for factories in Django is pretty simple, is this of interest?

class ManyToManyPostGeneration(factory.PostGeneration):
    """
    Simplified factory post_generation for many-to-many relationships - sets values passed to the collection
    https://factoryboy.readthedocs.io/en/latest/recipes.html?highlight=many#simple-many-to-many-relationship

    Arguments:
        name: the name of the many-to-many relation

    Usage:
        You can pass the factory a list of model instances

        - article_factory.create(tags=LazyFixture(lambda tag: [tag])))

        Or you can use the parametrize decorator

        - @pytest.mark.parametrize('article__tags', [LazyFixture(lambda tag: [tag])])
    """
    def __init__(self, name):
        def func(self, create, extracted, **kwargs):
            if create and extracted:
                getattr(self, name).set(extracted)
        func.__name__ = name
        return super().__init__(func)

Makes basic m2m declarations as simple as

class ArticleFactory(factory.django.DjangoModelFactory):
    tags = ManyToManyPostGeneration('tags')

You can also define and use the inverse side too

class TagFactory(factory.django.DjangoModelFactory):
    articles = ManyToManyPostGeneration('articles')

I'd drop the string arg but I couldn't figure out how to know the relation name otherwise

Another thought was whether it should add or set – the examples provided use add but I figure given the whole list is passed in an explicit set is probably what is expected (i.e. clobber)

Any interest in something like this in pytest-factoryboy?

Override sequence counter

I'd like to override the sequence counter.

My first attempt:

# models.py
from django.db import models

class Foo(models.Model):
    a = models.IntegerField()
    b = models.IntegerField()

# factories.py
from factory import DjangoModelFactory, Sequence
from .models import Foo

class FooFactory(DjangoModelFactory):
    class Meta:
        model = Foo

    a = Sequence(lambda x: x)
    b = Sequence(lambda x: x)

# test_one.py
from pytest_factoryboy import register
from .factories import FooFactory

register(FooFactory, __sequence=8)

@pytest.fixture
def foo__sequence():
    return 9

@pytest.fixture
def foo____sequence():
    return 10

def test_1(db, foo):
    assert foo.a in (8, 9, 10)

I ended up with the following workaround:

# factories.py
from factory import DjangoModelFactory, Sequence, SelfAttribute
from .models import Foo

class FooFactory(DjangoModelFactory):
    class Meta:
        model = Foo
        exclude = ('i',)

    i = Sequence(lambda x: x)
    a = SelfAttribute('i')
    b = SelfAttribute('i')

# test_one.py
from pytest_factoryboy import register
from .factories import FooFactory

register(FooFactory, i=8)

@pytest.fixture
def foo__i():
    return 9

def test_1(db, foo):
    assert foo.a in (8, 9)
    assert foo.b in (8, 9)

Either register or foo__i work, no need for both of course.

The workaround is simple, so it may suffice to just note the workaround in the docs for now. Or if I've missed something, please let me know.

Thanks for the nice plugin.

@register decorator is incompatible with circular imports

Factoryboy documents the creation of circular dependencies like this:

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

    username = 'john'
    main_group = factory.SubFactory('users.factories.GroupFactory')

class GroupFactory(factory.Factory):
    class Meta:
        model = Group

    name = "MyGroup"
    owner = factory.SubFactory(UserFactory)

That example will not work with the @register decorator:

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

    username = 'john'
    main_group = factory.SubFactory('users.factories.GroupFactory')

@register
class GroupFactory(factory.Factory):
    class Meta:
        model = Group

    name = "MyGroup"
    owner = factory.SubFactory(UserFactory)

Throws:

ImportError while loading conftest '/app/_python/conftest.py'.
conftest.py:58: in <module>
    class UserFactory(factory.Factory):
/usr/local/lib/python3.5/site-packages/pytest_factoryboy/fixture.py:91: in register
    subfactory_class = value.get_factory()
/usr/local/lib/python3.5/site-packages/factory/declarations.py:647: in get_factory
    return self.factory_wrapper.get()
/usr/local/lib/python3.5/site-packages/factory/declarations.py:363: in get
    self.name,
/usr/local/lib/python3.5/site-packages/factory/utils.py:20: in import_object
    return getattr(module, str(attribute_name))
E   AttributeError: module 'conftest' has no attribute 'GroupFactory'

The issue seems to be that @register resolves the imports when applied, before the later classes are defined. So a workaround is to use the non-decorator version at the end of the file. This works:

# same as first code block, then ...
register(UserFactory)
register(GroupFactory)

Ideally the decorator form could Just Work, by delaying resolution of the imports until needed. Alternatively maybe the problem could be documented, and register() could detect what's happening and throw a more useful error?

Scope

There appears to be no way to define the scope of the resulting fixtures. Not sure if this is unsupported or undocumented, but it is a needed feature. Creating a new fixture scoped for "module" or "session" is not workable as the scope change results in an exception. Currently, all registered Factories are 'function' scoped.

Factory not registering as fixture

Hey there,

I'm trying to set up a basic test per this example:
https://pytest-factoryboy.readthedocs.io/en/latest/#integration

When my tests check whether company_factory is an instance of CompanyFactory, the test fails.

Why isn't company_factory being instantiated?

Here's my code:

# tests/test_company.py
import pytest

from .factories import CompanyFactory
from project.apps.company.models import Company

def test_company_factory(company_factory):
    assert isinstance(company_factory, CompanyFactory) # passes

def test_company_model(db, company):
    assert isinstance(company, Company) # fails
    # message:  where False = isinstance(<class 'tests.factories.CompanyFactory'>, CompanyFactory)**
# tests/factories.py
class CompanyFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = 'company.Company'
    
    name = 'company'
    # other attributes ...

# tests/conftest.py
import pytest
from pytest_factoryboy import register

from .factories import CompanyFactory

register(CompanyFactory)

pytest 5.4.0 compatibility

Tests failing

============================================================================================================ ERRORS =============================================================================================================
________________________________________________________________________________________ ERROR collecting tests/test_factory_fixtures.py ________________________________________________________________________________________
In function "test_parametrized":
Parameter "edition__year" should be declared explicitly via indirect or in function itself
__________________________________________________________________________________________ ERROR collecting tests/test_lazy_fixture.py __________________________________________________________________________________________
In function "test_lazy_attribute":
Parameter "user__password" should be declared explicitly via indirect or in function itself
______________________________________________________________________________________ ERROR collecting tests/test_postgen_dependencies.py ______________________________________________________________________________________
In function "test_depends_on":
Parameter "foo__expected" should be declared explicitly via indirect or in function itself

Errors with factory_boy master: 'FactoryOptions' object has no attribute 'postgen_declarations'

There are errors with factory_boy master:

================================================ ERRORS ================================================
_______________________________ ERROR collecting tests/test_circular.py ________________________________
tests/test_circular.py:50: in <module>
    register(AuthorFactory)
.tox/py36-pytest3/lib/python3.6/site-packages/pytest_factoryboy/fixture.py:60: in register
    deps = get_deps(factory_class, model_name=model_name)
.tox/py36-pytest3/lib/python3.6/site-packages/pytest_factoryboy/fixture.py:154: in get_deps
    for attr, value in factory_class.declarations(factory_class._meta.postgen_declarations).items()
E   AttributeError: 'FactoryOptions' object has no attribute 'postgen_declarations'
___________________________ ERROR collecting tests/test_factory_fixtures.py ____________________________
tests/test_factory_fixtures.py:56: in <module>
    class AuthorFactory(factory.Factory):
.tox/py36-pytest3/lib/python3.6/site-packages/pytest_factoryboy/fixture.py:60: in register
    deps = get_deps(factory_class, model_name=model_name)
.tox/py36-pytest3/lib/python3.6/site-packages/pytest_factoryboy/fixture.py:154: in get_deps
    for attr, value in factory_class.declarations(factory_class._meta.postgen_declarations).items()
E   AttributeError: 'FactoryOptions' object has no attribute 'postgen_declarations'
_____________________________ ERROR collecting tests/test_lazy_fixture.py ______________________________
tests/test_lazy_fixture.py:29: in <module>
    register(UserFactory)
.tox/py36-pytest3/lib/python3.6/site-packages/pytest_factoryboy/fixture.py:60: in register
    deps = get_deps(factory_class, model_name=model_name)
.tox/py36-pytest3/lib/python3.6/site-packages/pytest_factoryboy/fixture.py:154: in get_deps
    for attr, value in factory_class.declarations(factory_class._meta.postgen_declarations).items()
E   AttributeError: 'FactoryOptions' object has no attribute 'postgen_declarations'
_________________________ ERROR collecting tests/test_postgen_dependencies.py __________________________
tests/test_postgen_dependencies.py:23: in <module>
    class FooFactory(factory.Factory):
.tox/py36-pytest3/lib/python3.6/site-packages/pytest_factoryboy/fixture.py:60: in register
    deps = get_deps(factory_class, model_name=model_name)
.tox/py36-pytest3/lib/python3.6/site-packages/pytest_factoryboy/fixture.py:154: in get_deps
    for attr, value in factory_class.declarations(factory_class._meta.postgen_declarations).items()
E   AttributeError: 'FactoryOptions' object has no attribute 'postgen_declarations'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 4 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
======================================= 4 error in 0.30 seconds ========================================
ERROR: InvocationError: '…/Vcs/pytest-factoryboy/.tox/py36-pytest3/bin/py.test --junitxml=…/Vcs/pytest-factoryboy/.tox/py36-pytest3/log/junit-py36-pytest3.xml pytest_factoryboy tests'
_______________________________________________ summary ________________________________________________
ERROR:   py36-pytest3: commands failed

Bisecting brings up the following commits (2 are skipped, since they cause a different error):

FactoryBoy/factory_boy@c079d87
FactoryBoy/factory_boy@e447662
FactoryBoy/factory_boy@6f20207

Likely related to the refactoring mentioned in #23 (comment).

TypeError: can only concatenate str (not "PostGenerationMethodCall") to str

When using factory.PostGenerationMethodCall on a factory I get the type error in the title.

The factory I'm working with is a django user model. Simple example:

class UserFactory(factory.django.DjangoModelFactory):
    email = factory.Sequence(lambda n: "user-{0}@example.com".format(n))
    password = factory.PostGenerationMethodCall("set_password", ["password"])
    first_name = fuzzy.FuzzyText(length=20)
    last_name = fuzzy.FuzzyText(length=20)

    class Meta:
        model = "users.User"
        django_get_or_create = ("email",)

register(UserFactory)

Attempting to use that factory as a fixture will throw:

env/lib/python3.7/site-packages/pytest_factoryboy/plugin.py:83: in evaluate
    self.execute(request, function, deferred)
env/lib/python3.7/site-packages/pytest_factoryboy/plugin.py:65: in execute
    self.results[model][attr] = function(request)
env/lib/python3.7/site-packages/pytest_factoryboy/fixture.py:273: in deferred
    declaration.call(instance, step, context)
env/lib/python3.7/site-packages/factory/declarations.py:743: in call
    return method(*args, **kwargs)
env/lib/python3.7/site-packages/django/contrib/auth/base_user.py:98: in set_password
    self.password = make_password(raw_password)
env/lib/python3.7/site-packages/django/contrib/auth/hashers.py:78: in make_password
    return hasher.encode(password, salt)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <django.contrib.auth.hashers.MD5PasswordHasher object at 0x7f1fa3759cd0>, password = <factory.declarations.PostGenerationMethodCall object at 0x7f1fa47ff390>, salt = 'XXXXXXXXX'

    def encode(self, password, salt):
        assert password is not None
        assert salt and '$' not in salt
>       hash = hashlib.md5((salt + password).encode()).hexdigest()
E       TypeError: can only concatenate str (not "PostGenerationMethodCall") to str

env/lib/python3.7/site-packages/django/contrib/auth/hashers.py:508: TypeError

The error stems from

if isinstance(value, factory.declarations.PostGeneration):
.

Changing that check to something like:

        if isinstance(value, factory.declarations.PostGeneration) or isinstance(
                value, factory.declarations.PostGenerationMethodCall
            ):

Seems to fix the issue. I haven't looked at this closely though so not sure if that's the best solution.

possibly relevant versions:
pytest-factoryboy==2.0.3
django==2.2.6
factory-boy==2.12.0
pytest-django==3.6.0

Allow disabling Subfactory fixture replacing - might create circular dependencies

Because pytest-factoryboy replaces SubFactory with registered factories, it is possible to inadvertently create circular dependencies, which are not detected by pytest.

In my case, the setup was the following:

  1. User factory
  2. Company factory with a Contact subfactory.
  3. user fixture overridden in the test file, depending on the company fixture
  4. contact fixture overridden in the same file, depending on the company fixture.

Normally it should be fine because user -> company and contact -> company - there's no cycle. But, because the plugin creates a dependency company -> contact, the graph becomes: user -> company -> contact -> company and there's a cycle. Yet this cycle is a bit magical - I did not ask for company.contact and contact.company to be the same... I want a new, unrelated contact to be created for each company.

Would it be possible to add an option to disable this for those who don't need it? Or only some whitelisted subfactories? In my case, I would like the company.contact factory to be unrelated to the contact factory.

factory.DictFactory fixtures have incorrect names

Here's a reproduction:

import factory
from pytest_factoryboy import register


@register
class OAuthPayloadFactory(factory.DictFactory):
    """Fake factory for OAuth payload response."""

    refresh_token = 'some-token'
    access_token = 'some-refresh-token'
    token_type = 'bearer'
    expires_in = 0

When trying to access this fixture I get an error:

@pytest.fixture()
def access_token(o_auth_payload):  # failing here: o_auth_payload is not found
    """A demo fixture to illustrate the issue."""
    return o_auth_payload['access_token']

What I expect to happen

I expect that o_auth_payload would be injected as a fixture.

What actually happens

  @pytest.fixture()
  def user_email(user, o_auth_payload, user_payload):
E       fixture 'o_auth_payload' not found
>       available fixtures:

pytest --fixtures output

dict
    <string>:3: no docstring available
dict__access_token
    <string>:3: no docstring available
dict__expires_in
    <string>:3: no docstring available
dict__refresh_token
    <string>:3: no docstring available
dict__token_type
    <string>:3: no docstring available
o_auth_payload_factory
    <string>:3: no docstring available

env

  • pytest==3.6.1
  • pytest-factoryboy==2.0.1
  • factory-boy==2.11.1

What sorcery is this?

I am trying to make some tests and this is my first time using pytest-factoryboy. I would like to understand why my does my print() doesn't print the same for both objects. I thought they were from the same class (UserFactory).

conftest.py

from pytest_factoryboy import register
from bin.tests.factories import UserFactory

register(UserFactory)

factories.py

import factory
from pytest_factoryboy import register
from faker import Factory as FakerFactory
import datetime
import pytest
from bin import models

fake = FakerFactory.create()


@register
class UserFactory(factory.django.DjangoModelFactory):

    class Meta:
        model = models.User
        django_get_or_create = ('username',)

    username = factory.LazyAttribute(lambda n: fake.user_name())
    email = factory.LazyAttribute(lambda n: fake.safe_email())
    first_name = factory.LazyAttribute(lambda n: fake.first_name_female())
    last_name = factory.LazyAttribute(lambda n: fake.last_name_female())

    def __init__(self, *args, **kwargs):
        super(UserFactory, self).__init__(*args, **kwargs)
        self.set_password('1234')

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        """Override the default ``_create`` with our custom call."""
        manager = cls._get_manager(model_class)
        # The default would use ``manager.create(*args, **kwargs)``
        user = manager.create_user(*args, **kwargs)
        user.is_active = True
        user.save()
        return user

test_user.py

import pytest
from django.core.urlresolvers import reverse
from django.conf import settings


class TestUser:
    @pytest.mark.integration
    def test_user_gets_locked_after_unsuccessful_attempts(self, db, user_factory, client):
        client.get(reverse('logout'))

        for _ in range(0, 10):
            response = client.post(
                reverse('login'),
                {
                    'username': user_factory.username,
                    'password': 'some_wrong_password'
                }
            )

        print(user_factory.username)
        another_user = UserFactory()
        print(another_user.username)

        assert user_factory.profile.pwd_attempts > 9
        assert not user_factory.is_active

Ouput

bin/tests/test_user.py:27: AttributeError
----------------------------- Captured stdout call -----------------------------
<UserFactory for <class 'django.contrib.auth.models.User'>>
tinamendoza

Possible for `register` to use factory docstring

Using the convenience register method to register fixtures does not import the docstring. Running pytest --fixtures results in no docstring available for all pytest-factoryboy fixtures.
It would be nice to include a docstring arg to the register method e.g

register(UserFactory, _name="special_user", _docstring="Useful sentence describing this fixture")

Thanks for the library it is very handy!

Are factory.django.DjangoModelFactory fixtures in conftest.py available across applications?

pytest-dev/pytest-django#508

I'm using factory_boy with https://github.com/pytest-dev/pytest-django.

python: 3.6.2
django: 1.11.4
pytest-django: 3.1.2
factory-boy: 2.8.1 (downgraded due to #47 (comment))
pytest-factoryboy: 1.3.1

Here's my app1/conftest.py:

# -*- coding: utf-8 -*-
import factory
import pytest
from django.contrib.auth import get_user_model
from django.core.management import call_command
from pytest_factoryboy import register

class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = get_user_model()

    username = factory.Sequence(lambda n: "user%03d" % n)
    password = factory.Sequence(lambda n: "pass%03d" % n)

register(UserFactory)

This makes user available as a fixture for me. However, it only works in tests in the same application, not project-wide (in different django application test directories).

Am I doing it wrong, then? I'm trying to narrow down if this is a mistake on my end, a bug, a potential feature, or expected behavior.

Register sub-classed factories as instance fixtures?

Given the following factories:

class BookFactory(factory.django.DjangoModelFactory):
    title = factory.LazyAttribute(lambda x: faker.sentence(nb_words=4))
    pub_date = factory.LazyAttribute(lambda x: faker.date())

    class Meta:
        model = Book

    author = factory.SubFactory(AuthorFactory)

class RedBookFactory(BookFactory):
    pass

class NovelFactory(BookFactory):
    pass

I was a bit confused at first as to why red_book and novel fixtures were not being created, but after looking at the code, it looks like the factory's model drives these instance fixtures.

Any interest in creating these fixtures? If not, what's the reasoning?

If anything, maybe add this example to the documentation, showing that the factory fixtures register (red_book_factory and novel_factory) but not the instance fixtures (red_book and novel).

Exception when using pytest-factoryboy with pytest-xdist

I run py.test -n auto and got this:

    @pytest.mark.tryfirst
    def pytest_runtest_call(item):
        """Before the test item is called."""
        try:
            request = item._request
        except AttributeError:
            # pytest-pep8 plugin passes Pep8Item here during tests.
            return
        factoryboy_request = request.getfuncargvalue("factoryboy_request")
        factoryboy_request.evaluate()
        factoryboy_request.is_finalized = True
>       request.config.hook.pytest_factoryboy_done(request=request)
E       AttributeError: _HookRelay instance has no attribute 'pytest_factoryboy_done'

Usage of django.ImageField leads to fixture 'dict' not found

Using a factory with a django.Image field leads to error fixture 'dict' not found.

Sample:

from factory.django import DjangoModelFactory, ImageField
from pytest_factoryboy import register

from . import models

class AttachmentFactory(DjangoModelFactory):
    path = ImageField(width=1024, height=768)

    class Meta:
        model = models.Attachment

register(AttachmentFactory)

# this test will lead to `fixture 'dict' not found` error
def test_attachment(attachment):
  # some tests

This happens with following dependencies:

factory-boy==2.10.0
pytest-factoryboy==2.0.1

This worked without any problems with these dependencies:

factory-boy==2.8.1
pytest-factoryboy==1.3.2

Integration sample with SqlAlchemy ?

Hi how would an integration with sqlalchemy works here ??, especially with the scoped_session

I currently have this conftest.py setup on my flask project:

@pytest.fixture(scope='session')
def app(request):
    """Session-wide test `Flask` application."""
    app = create_app('testing')

    # Establish an application context before running the tests.
    ctx = app.app_context()
    ctx.push()

    def teardown():
        ctx.pop()

    request.addfinalizer(teardown)
    return app


@pytest.fixture(scope='session')
def db(app, request):
    """Session-wide test database."""
    def teardown():
        _db.drop_all()

    _db.app = app
    _db.create_all()

    request.addfinalizer(teardown)
    return _db


@pytest.fixture(scope='function')
def session(db, request):
    """Creates a new database session for a test."""
    # connect to the database
    connection = db.engine.connect()
    # begin a non-ORM transaction
    transaction = connection.begin()

    # bind an individual session to the connection
    options = dict(bind=connection, binds={})
    session = db.create_scoped_session(options=options)

    # overload the default session with the session above
    db.session = session

    def teardown():
        session.close()
        # rollback - everything that happened with the
        # session above (including calls to commit())
        # is rolled back.
        transaction.rollback()
        # return connection to the Engine
        connection.close()

    request.addfinalizer(teardown)
    return session

# basically instead of creating and dropping the database for each test
# i just rollback the transaction.
# this setup works perfectly fine without using factory boy

I've been searching around the internet on how to make Factory Boy use the same session fixture that pytest use. And then stumble upon this library, but upon looking into the examples, I cant figure how I or this library would do the same.

flake8-3.0.0 breaks pytest-factoryboy

when having pytest-factoryboy and flake8-3.0.0 packages installed in the environment, pytest-factoryboy will fail registering as a pytest plugin.

common scenario when using pytest-flake8 for instance.

I'll try to see the reason but maybe it's easy enough for someone with more knowledge in the project

LazyFixture ignores Subfactory attribute assignment

I am using pytest-factoryboy to test some of my django Code.

When using A model 'MainModel' with a ForeignKey to another Model 'OneOnly' I create a Factory for both like the following.

models.py:

from django.db import models


class OnlyOne(models.Model):
    name = models.CharField(max_length=16)


class MainModel(models.Model):
    name = models.CharField(max_length=16)
    one = models.ForeignKey(OnlyOne)

factories.py

import factory
import factory.fuzzy

from bug.models import MainModel
from bug.models import OnlyOne


class OnlyOneFactory(factory.DjangoModelFactory):
    class Meta(object):
        model = OnlyOne

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


class MainModelFactory(factory.DjangoModelFactory):
    class Meta(object):
        model = MainModel

    name = factory.Sequence(lambda n: 'MainModel {}'.format(n))
    one = factory.SubFactory(OnlyOneFactory, name='Initial Name')

So I want the Subfactory to set OnlyOnes' name always to Initial Name. As of the documentation this is how to do it (see example here ):
one = factory.SubFactory(OnlyOneFactory, name='Initial Name')

Now I have written some basic tests to test that the name of OnlyOne is set correctly. And it is if I use the factory build and/or create method, but however not if I use the LazyFixture.

test_factories.py:

"""Test the factories."""
import pytest


@pytest.mark.django_db
def test_main_model_factory__create(main_model_factory):
    """Test if the MainModelFactory.create() works properly."""
    main_model = main_model_factory.create()
    assert main_model.one.name == 'Initial Name'


@pytest.mark.django_db
def test_main_model_factory__build(main_model_factory):
    """Test if the MainModelFactory.build() works properly."""
    main_model = main_model_factory.build()
    assert main_model.one.name == 'Initial Name'


@pytest.mark.django_db
def test_main_model_fixture(main_model):
    """Test if the MainModelFactory shortcut works properly."""
    assert main_model.one.name == 'Initial Name'

Test output is the following:

pytest
=========================================================== test session starts ============================================================
platform linux2 -- Python 2.7.12+, pytest-3.0.3, py-1.4.31, pluggy-0.4.0
django settings: factoryboy_subfactory_attribute_bug.settings (from ini file)
rootdir: /home/daniel/workspace/private/factoryboy_subfactory_attribute_bug/factoryboy_subfactory_attribute_bug, inifile: pytest.ini
plugins: bdd-2.18.0, factoryboy-1.1.6, django-2.9.1, timeout-1.0.0, blockage-0.2.0, cov-2.4.0
collected 3 items 

bug/tests/test_factories.py ..F

================================================================= FAILURES =================================================================
_________________________________________________________ test_main_model_fixture __________________________________________________________

main_model = <MainModel: MainModel object>

    @pytest.mark.django_db
    def test_main_model_fixture(main_model):
        """Test if the MainModelFactory shortcut works properly."""
>       assert main_model.one.name == 'Initial Name'
E       assert 'OnlyOne 2' == 'Initial Name'
E         - OnlyOne 2
E         + Initial Name

bug/tests/test_factories.py:22: AssertionError
==================================================== 1 failed, 2 passed in 0.32 seconds ====================================================

The question now is should it set the name as expected or am I misunderstanding the functionality of the LazyFixture used?

I am attaching a sample.tar.gz with a working django app to simulate this.
sample.tar.gz

  1. Unpack and cd to folder
  2. virtualenv env -p python3
  3. pip install django python-factoryboy pytest
  4. run pytest

Thanks for the help.

Edit: If you need any further information please feel free to ask. Sorry if something is missing I am new to submitting Issues on an open source project.

[Feature request] Traits as fixtures?

Hi,

I'd like to parametrize use of a Factoryboy Trait. But i don't see my Traits when i list my fixtures, so i get there is something missing here.

I honestly don't know if that would even be possible, so if it's not, please explain why ;)
Thanks

Release new version on pypi

Using pytest-factoryboy with the newest pytest currently generates a lot of deprecation warnings. This is fixed in #62, but hasn't been released on pypi yet. Could you please create a new release?

Using `factory.List` resolves in unusable fixtures

Setup

Here are my models:

from typing import List

from mypy_extensions import TypedDict


class WakatimeCommit(TypedDict):
    """Class to represent a single Wakatime commit instance from API. """

    hash: str
    author_email: str


class WakatimeCommitsResponse(TypedDict):
    """Class to represent Wakatime response from commits API."""

    commits: List[WakatimeCommit]

And my factories:

import factory
from pytest_factoryboy import register

@register
class WakatimeCommitFactory(factory.BaseDictFactory):
    """
    Fake factory for a single Wakatime commit entry.

    Note:
        This class is marked as protected and is not registered,
        since we do not actually need a single commit in tests.

    """

    class Meta(object):
        model = WakatimeCommit

    hash = '123abc'
    author_email = '[email protected]'


@register
class WakatimeCommitsResponseFactory(factory.BaseDictFactory):
    """Fake factory for Wakatime `/commits` response."""

    class Meta(object):
        model = WakatimeCommitsResponse

    commits = factory.List([
        factory.SubFactory(WakatimeCommitFactory) for _ in range(10)
    ])

And finally my test:

def test_pipeline_for_opened_valid_mr(
    wakatime_commits_response,
):
    """
    Tests the whole process of adding spent time to a merge request.

    All requests are mocked, everything returns valid responses.
    """
    print(wakatime_commits_response)

    assert 1 == 2

Error

This tests fails due to unresolved fixtures:

def test_pipeline_for_opened_valid_mr(
file <string>, line 2: source code not available
file <string>, line 2: source code not available
E       fixture 'list' not found
>       available fixtures:
...
wakatime_commit, wakatime_commit__author_email, wakatime_commit__hash, wakatime_commit__total_seconds, wakatime_commit_factory, wakatime_commits_response, wakatime_commits_response__commits, wakatime_commits_response_factory
...

I guess this happens due to the fact that I am using factory.List.

Workaround

class WakatimeCommitsResponseFactory(factory.BaseDictFactory):
    ...

    @factory.post_generation
    def commits(self, create, extracted, **kwargs):
        if extracted:
            self['commits'] = extracted
        else:
            self['commits'] = []
            for _ in range(10):
                self['commits'].append(WakatimeCommitFactory.build())

SubFactory uses wrong fixture name when factory class registered with different model_name

It appears that when processing SubFactory attributes on the parent factory and generating deps for the SubFactory fixture, the introspected names do not take into account whether a given factory was registered earlier with a different model_name.

This gist demonstrates a failing test where the generated SubFactory fixture is expecting to find a b_model__name fixture when the one available is actually named b_model_with_some_other_name__name.
https://gist.github.com/ryancausey/904ad5b77349769d32c72d413dd79a59

I think the root cause of all the issues I'm experiencing can be boiled down to this. This generally shows up when a second factory class is created from a parent subclass. Using the documentation's AuthorFactory as an example:

class BobAuthorFactory(AuthorFactory):
    name = "Bob"

register(BobAuthorFactory, "author_bob")

If we create a second BookFactory subclass that uses BobAuthorFactory as the SubFactory:

class BobBookFactory(BookFactory):
    author = factory.SubFactory(BobAuthorFactory)

register(BobBookFactory, "book_bob")

Then any use of book_bob will actually end up using the original author fixture and end up with an author whose name is "Charles Dickens" based on the docs at the time of this writing.

It doesn't appear that there's an easy fix for register to be able to look up what model_name a given factory class was registered with so I don't have a good answer on how to fix this right now.

Partial specialization with custom post_generation for M2M

I may be missing something, but I am having trouble registering a "partial specialization" fixture for a factory with a ManyToMany field.

I tried using [the example in factoryboy docs][1], combined with the example in fixture attributes, but it throws TypeError: int() argument must be a string or a number, not 'LazyFixture'. Is this something we can even do?

Here's a test case:

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

    name = "John Doe"

    @factory.post_generation
    def groups(self, create, extracted, **kwargs):
        if not create:
            # Simple build, do nothing.
            return

        if extracted:
            # A list of groups were passed in, use them
            for group in extracted:
                self.groups.add(group)

register(UserFactory, "special_user", groups=[LazyFixture("group")])

parametrize + pytest-bdd + pytest-factoryboy problem?

Hi
I try this and 'navigator' parameter is not overrided by the 'yoshi' fixture...
Is this valid code?

@pytest.mark.parametrize('navigator', [LazyFixture("yoshi")])
@given('I am on the Registration Page')
def i_am_on_the_registration_page(navigator):
    """I am on the Registration Page."""
    navigator.load_index().login().load_registration()

Allow passing fixtures that pytest-factory's fixtures should depend on

I have the following fixtures:

@pytest.yield_fixture(scope='session')
def db_url():
    with testing.postgresql.Postgresql() as db:
        yield db.url()


@pytest.yield_fixture
def db(db_url):
    """Create a database session."""
    engine = sqlalchemy.create_engine(db_url)

    models.metadata.create_all(engine)

    factories.Session.configure(bind=engine)
    session = factories.Session()  # creates the thread local session used by factories
    yield session
    session.rollback()
    factories.Session.remove()  # disables the thread local session

    models.metadata.drop_all(engine)


pytest_factoryboy.register(factories.BookFactory)

My problem now is that trying to use the book_factory fixture on its own doesn't work; I need the db fixture to open a session the factory can use, first.

I'd like to be able to specify something like

pytest_factoryboy.register(factories.BookFactory, depends_on=['db'])

which would have the same effect as the manual implementation of

def book_factory(db):
    # …

would.

Registered Django factories don't call overridden classmethod _create

It seems only the _create of the parent class (factory.django.DjangoModelFactory._create) is called when using a pytest-factoryboy fixture in a test. Using the Factory() class directly works fine (does indeed call the Factory._create classmethod).

I'll try to add a test case, but it will require adding a bunch of new requirements if we want to test it for a real Django model factory.

RelatedFactoryList size not working

Example:

# models

from django.db import models


class Article(models.Model):
    title = models.CharField(max_length=1000)


class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
    text = models.TextField()

# conftest.py

class CommentFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Comment

    article = factory.SubFactory("tests.conftest.ArticleFactory")
    text = faker.text()


class ArticleFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Article

    title = faker.sentence(nb_words=4)

    # This only returns 1 comment if loaded through pytest-factoryboy
    comment_set = factory.RelatedFactoryList(CommentFactory, "article", size=5)


@pytest.fixture()
def article1():
    yield ArticleFactory()


register(CommentFactory)
register(ArticleFactory)

# Tests

@pytest.mark.django_db
class TestComments:
    def test_fails_to_create_5_comments(self, graphql_client, article):
        assert article.comment_set.count() == 5  # fails, always returns 1

    def test_creates_5_comments(self, graphql_client, article1):
        assert article1.comment_set.count() == 5

No parameters generated for model-only attributres

No parameters are generated for model-only parameters. We often have Django model defaults which we don't override in factories, but do override in tests. For example:

class Book(models.Model):
    title = models.CharField(max_length=255, default='My title')


class BookFactory(factory.DjangoModelFactory):
    class Meta:
        model = Book


register(BookFactory)


@pytest.mark.django_db
@pytest.mark.parametrize('book__title', ['My other title'])
def test_title(book):
    assert book.title == 'My other title'

This results in ValueError: <function test_title at 0x7efe970a2488> uses no fixture 'book__title'

If I add the title to the BookFactory it does work.

Result of pip freeze:

Django==1.9.6
factory-boy==2.7.0
fake-factory==0.5.7
inflection==0.3.1
ipaddress==1.0.16
py==1.4.31
pytest==2.9.1
pytest-django==2.9.1
pytest-factoryboy==1.1.6
python-dateutil==2.5.3
six==1.10.0

fixture 'author' not found

import factory
from pytest_factoryboy import register

@register
class AuthorFactory(factory.Factory):

    class Meta:
        model = Author

    name = "Charles Dickens"


def test_model_fixture(author):
    assert author.name == "Charles Dickens"

Get error '"author" is not found', only works with author_factory

CI is failing since pytest-cov is not pegged and requires pytest > 3.6

As seen in travis fails here:
https://travis-ci.org/pytest-dev/pytest-factoryboy/jobs/552058354

Support drop of pytest < 3.6 is mentioned in pytest-cov release notes here: https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst#260-2018-09-03

We can either peg pytest-cov in our

to e.g pytest-cov<2.6 ; or, we can drop support for pytest < 3.6 as well, in our travis/tox configurations.

Since last release was a while ago, I lean towards the latter, with a 2.1 release noting this breaking change.

What say you @pytest-dev ?

pytest-factoryboy do not work with pytest 3.0

When trying to use pytest-factoryboy with newest pytest, exception occurs:

____________________________________________________________________ ERROR at setup of test_asdf ____________________________________________________________________

request = <SubRequest 'xyz' for <Function 'test_asdf'>>, factory_name = 'xyz_factory'

    def model_fixture(request, factory_name):
        """Model fixture implementation."""
        factoryboy_request = request.getfuncargvalue("factoryboy_request")

        # Try to evaluate as much post-generation dependencies as possible
        factoryboy_request.evaluate(request)

        factory_class = request.getfuncargvalue(factory_name)
        prefix = "".join((request.fixturename, SEPARATOR))
        data = {}
        for argname in request._fixturedef.argnames:
            if argname.startswith(prefix) and argname[len(prefix):] not in factory_class._meta.postgen_declarations:
                data[argname[len(prefix):]] = request.getfuncargvalue(argname)

        class Factory(factory_class):

            @classmethod
            def attributes(cls, create=False, extra=None):
                return dict(
                    (key, evaluate(request, value))
                    for key, value in super(Factory, cls).attributes(create=create, extra=extra).items()
                    if key in data
                )

        Factory._meta.postgen_declarations = {}
        Factory._meta.exclude = [value for value in Factory._meta.exclude if value in data]

        # Extract post-generation context
        post_decls = []
        if factory_class._meta.postgen_declarations:
            for attr, decl in sorted(factory_class._meta.postgen_declarations.items()):
                post_decls.append((attr, decl, decl.extract(attr, data)))

        # Create model fixture instance
        instance = Factory(**data)
        request._fixturedef.cached_result = (instance, None, None)
>       request._fixturedefs[request.fixturename] = request._fixturedef
E       AttributeError: SubRequest instance has no attribute '_fixturedefs'

<snip>/lib/python2.7/site-packages/pytest_factoryboy/fixture.py:200: AttributeError

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.