I am trying to write a test for an UpdateView I created.
My view looks like this:
class MutantUpdateView(UpdateView):
context_object_name = "mutant"
fields = ["mutation_level"]
model = Mutant
pk_url_kwarg = "mutant_id"
template_name_suffix = "_update_form"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["admin"] = get_object_or_404(
Person, id=self.kwargs["admin_id"]
)
context["backstory"] = get_object_or_404(
Backstory, id=self.kwargs["backstory_id"]
)
context["evidences"] = self.object.evidences.all()
return context
def get_form(self, form_class=None):
form = super().get_form(form_class)
mutant = self.object
mutation_levels = (
mutant.expectation.mutation_levels.all()
)
form.fields["mutation_level"].queryset = mutation_levels
return form
def form_valid(self, form):
form.instance.updated_by = = get_object_or_404(
Person, id=self.request.user.person_id
)
return super().form_valid(form)
def get_success_url(self, **kwargs):
return reverse_lazy(
"mutants:mutant-update",
kwargs={
"admin_id": self.kwargs["admin_id"],
"backstory_id": self.kwargs["backstory_id"],
"mutant_id": self.kwargs["mutant_id"],
},
)
My test looks like this (per the documentation)
def test_form_valid_posts_appropriately(self):
new_level = MutantLevelFactory(short_description="Next Mutant Level")
self.mutant.expectation.mutation_levels.add(new_level)
data = {
"created_by": self.admin_person.id,
"updated_by": self.admin_person.id,
"backstory": self.mutant.backstory.id,
"expectation_level": new_level,
"expectation": self.mutant.expectation.id,
}
kwargs = {
"admin_id": self.admin_person.id,
"backstory_id": self.mutant.backstory.id,
"mutant_id": self.mutant.id,
}
request = self.factory.get(
reverse("mutants:mutant-update", kwargs=kwargs)
)
request.user = self.admin_user # simulate admin user logged in
self.view.setup(request)
context = self.view.get_context_data()
self.assertIn('backstory', context)
self.assertFalse(context["form"].errors)
self.assertEqual(response.status_code, 302)
It's giving me this error:
def get_form(self, form_class=None):
form = super().get_form(form_class)
> mutant = self.object
E AttributeError: 'MutantUpdateView' object has no attribute 'object'
The model looks like this:
class Mutant(models.Model):
id = models.BigAutoField(primary_key=True)
backstory = models.ForeignKey(
Backstory, on_delete=models.PROTECT, related_name="%(class)ss"
)
expectation = models.ForeignKey(
Expectation, on_delete=models.PROTECT, related_name="%(class)ss"
)
mutation_level = models.ForeignKey(
MutationLevel,
on_delete=models.PROTECT,
null=True,
blank=True,
related_name="%(class)ss",
)
What is the best way to test a basic Django UpdateView? Is this the best way or should I be using the Client()
and making an integration type test? Ultimately I'd like to both unit test and integration test this view - if that's appropriate.
I've tried changing the code in various ways such as:
response = MutantUpdateView.as_view()(request, **kwargs)
but that didn't work either.
CodePudding user response:
The problem is not the view, but testing the view. Your test aims to "mimic" the code flow of the view, but the object is set in the .get(…)
method [classy-Django]. You likely can implement that too, but if you later change the view, or you add a mixin, etc. That will result in fixing all tests.
One usually uses the django test client [Django-doc] for this: a tool that will fake a request, and pass that through the view:
from django.test import TestCase
class MyTestCase(TestCase):
def test_form_valid_posts_appropriately(self):
self.client.force_login(self.admin_user)
new_level = MutantLevelFactory(short_description='Next Mutant Level')
self.mutant.expectation.mutation_levels.add(new_level)
data = {
'created_by': self.admin_person.id,
'updated_by': self.admin_person.id,
'backstory': self.mutant.backstory.id,
'expectation_level': new_level,
'expectation': self.mutant.expectation.id,
}
kwargs = {
'admin_id': self.admin_person.id,
'backstory_id': self.mutant.backstory.id,
'mutant_id': self.mutant.id,
}
response = self.client.post(
reverse('mutants:mutant-update', kwargs=kwargs), data
)
self.assertIn('backstory', response.context)
self.assertFalse(response.context['form'].errors)
self.assertEqual(response.status_code, 302)