-
-
Notifications
You must be signed in to change notification settings - Fork 102
Description
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 (
model_bakery/model_bakery/recipe.py
Line 54 in b90253b
| if k not in self._iterator_backups or m.objects.count() == 0: |
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