Django тестирование UpdateView - у объекта нет атрибута 'object'
Я пытаюсь написать тест для созданного мной UpdateView.
Мое представление выглядит следующим образом:
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"],
},
)
Мой тест выглядит следующим образом ( согласно документации)
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)
Выдает ошибку:
def get_form(self, form_class=None):
form = super().get_form(form_class)
> mutant = self.object
E AttributeError: 'MutantUpdateView' object has no attribute 'object'
Модель выглядит следующим образом:
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",
)
Каким образом лучше всего тестировать базовый Django UpdateView? Это лучший способ или мне следует использовать Client()
и сделать тест интеграционного типа? В конечном счете, я хотел бы и юнит-тестировать, и интегрировать это представление - если это уместно.
Я пробовал изменять код различными способами, такими как:
response = MutantUpdateView.as_view()(request, **kwargs)
но и это не сработало.
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.
Обычно для этого используется django test client [Django-doc]: инструмент, который будет имитировать запрос и передавать его через представление:
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)