model_bakery
model_bakery copied to clipboard
Multiple calls to prepare_recipe() within SimpleTestCase fails when recipe uses seq()
It doesn't seem possible to create multiple model instances using separate calls to prepare_recipe()
within a SimpleTestCase
if the recipe uses seq()
. This triggers a database call to m.objects.count()
in https://github.com/model-bakers/model_bakery/blob/main/model_bakery/recipe.py#L37 which is disallowed inside a SimpleTestCase
.
I didn't find this issue documented anywhere, although I may have missed it. It seems at least surprising if not a bug to have a database call in prepare_recipe()
since the purpose of that method is to instantiate but not save a model instance. If it turns out this is not fixable, perhaps adding documentation regarding this caveat is appropriate.
Expected behavior
The prepare_recipe()
method is always usable within SimpleTestCase
.
Actual behavior
The use of prepare_recipe()
within SimpleTestCase
fails when the recipe contains a seq()
and is called more than once.
Reproduction Steps
# models.py
from django.db import models
class MyModel(models.Model):
my_field = models.IntegerField()
# baker_recipes.py
from model_bakery.recipe import Recipe, seq
from .models import MyModel
my_model = Recipe(MyModel, my_field=seq(1))
# tests.py
from django.test import SimpleTestCase
from model_bakery import baker
class MyTest(SimpleTestCase):
def test_my_model(self):
# This test errors due to the db query to m.objects.count() in:
# https://github.com/model-bakers/model_bakery/blob/main/model_bakery/recipe.py#L37
# Note that baker.prepare_recipe('myapp.my_model', _quantity=2) would work in this simple example,
# but more complex situations may need instances created at separate points in the test
baker.prepare_recipe('myapp.my_model')
baker.prepare_recipe('myapp.my_model')
Versions
Python: 3.8.6 Django: 3.0.11 Model Bakery: 1.2.1
Hi @abbottc thanks for opening this issue.
Actually, you're right about this not being able to be fixed. There's a hack to "reset" the seq
call after the test finishes without creating any extra API for bakery. The hack is this query count you've noticed. The motivation behind this hack was: how to make the recipe to know that the seq
should start from the beginning once a second test uses it?
This is being explicitly tested by 2 test methods at test_recipes.py
:
The decision behind this was to not add extra parameters to make_recipe
or more complex pieces of code such as context managers or custom test runners to handle the iterator reset. Model-bakery always had this goal to be a test utility, not a Django app. That's why people doesn't even need to add it to INSTALLED_APPS
.
So, given this context, I totally agree with you that a comment on bakery's limitation to not be used with SimpleTestCase
due to internal optimized queries it can perform when using recipes is definitely a good thing. I think the best place to be updated is the recipes docs.
Happy baking =}
Hi @berinhard,
Thanks for following up on the issue and for the detail in explaining the rationale behind the query that gets executed in this scenario. If you'd like me to submit a PR making the minor doc addition, let me know.
Sure, that would be great!
Thanks, the PR is up.
@berinhard Also, thinking about what you explained regarding the query led me to consider other issues related to that which could be considered less minor than this issue, and I've documented an example in #209.