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.
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)