Skip to content

Calling prepare_recipe before make_recipe on a Recipe with a seq gives both records the same seq value #209

@abbottc

Description

@abbottc

For a Recipe with a seq, if a test calls prepare_recipe then later calls make_recipe, then the seq will give the same value in both calls, rather than incrementing values. So, if that prepared instance is saved later during the test, it would produce an unexpected database integrity error if it were a unique field, for example.

This issue is due to this line of code (

if k not in self._iterator_backups or m.objects.count() == 0:
) in which Recipe._mapping() uses m.objects.count() == 0 as a test to see whether to reset the seq. I believe the assumption made there is that the absence of records means seq is used for the first time in a new test and therefore should reset. However, an absence of records can occur in other ways in the middle of a test where seq should continue incrementing, as evidenced by this example.

This issue follows from the discussion in #132 in which @berinhard clarified the purpose for the count() query in relation to a more minor issue I ran into. Thinking about that led me to consider this situation related to the same code which I think is less minor.

I suspect a solution would require implementing an entirely different means to determine when seq should reset, and from the explanation in #132 I understand that several other means for that were already considered and ruled out. If this issue is deemed sufficiently problematic enough to fix via implementing an alternative reset determination, I'm happy to discuss and possibly follow with a PR, although I don't currently have a ready solution in mind.

Expected behavior

The seq method should provide incremental values rather than the same value when using both prepare_recipe and make_recipe in a test.

Actual behavior

The seq method provides the same value.

Reproduction Steps

# models.py

class MyModel(models.Model):
    # unique constraint not strictly needed except to demonstrate where this behavior can lead to errors
    my_field = models.IntegerField(unique=True)


# baker_recipes.py

my_model = Recipe(MyModel, my_field=seq(1))


# tests.py

class MyTest(TestCase):
    def test_my_model(self):
        model1 = baker.prepare_recipe('myapp.my_model')
        model2 = baker.make_recipe('myapp.my_model')
        # This would fail
        self.assertNotEqual(model1.my_field, model2.my_field)
        # ...or this would produce a database integrity error (due to the unique constraint)
        model1.save()

Versions

Python: 3.9.5
Django: 3.2.4
Model Bakery: 1.3.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions