我对一个UpdateView进行了测试:
当我在浏览器中浏览视图时,不会发生此行为,所以这与测试的运行方式有关。
instance.save()
有什么想法吗?
测试
class TestReviewUpdateView(TestCase):
def setUp(self):
self.review = ReviewFactory()
self.submission = self.review.submission
self.factory = RequestFactory()
self.kwargs = {'submission_pk': self.submission.pk}
def test_form_valid_with_object(self):
self.request = self.factory.post(reverse(
'submissions:review_update', kwargs=self.kwargs))
# Create user
self.request.user = StaffFactory()
view = views.ReviewUpdateView()
view.request = self.request
view.object = self.review
kwargs = {
'scores': self.review.get_list_of_scores()
}
form = forms.ReviewForm(**kwargs)
form.cleaned_data = {'axe_0': '4', 'axe_1': '4', 'axe_2': '4'}
response = view.form_valid(form)
assert response.status_code == 302
视图
class ReviewUpdateView(
BaseReviewForm,
UpdateView
):
""" A view for updating reviews. """
def dispatch(self, request, *args, **kwargs):
self.submission = self.get_submission()
self.conference = self.submission.conference
return super().dispatch(request, *args, **kwargs)
def get_submission(self):
return Submission.upcoming_objects.get_queryset(self.request.user).get(
pk=self.kwargs['submission_pk'])
def get_object(self):
return self.model.objects.get(
submission=self.submission,
user=self.request.user)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({
'scores': self.object.get_list_of_scores(),
})
return kwargs
def save_scores(self, form, instance):
for field in form.cleaned_data:
# The score fields will be numbers:
if "axe_" in field:
form_field = form.fields[field]
# Save the field's label as the key and score as value
instance.scores[form_field.label] = form.cleaned_data[field]
return instance
def form_valid(self, form):
instance = self.get_object()
instance = self.save_scores(form, instance)
instance.save()
return super().form_valid(form)
表格
class ReviewForm(forms.ModelForm):
""" Form for new reviews of submissions """
class Meta:
model = Review
fields = []
def __init__(self, *args, **kwargs):
review_fields = kwargs.pop("review_fields")
scores = kwargs.pop("scores")
super().__init__(*args, **kwargs)
if review_fields:
for i in review_fields:
self.fields["axe_%s" % i] = forms.ChoiceField(
choices=NUMBER_CHOICES,
label=review_fields[i],
widget=forms.RadioSelect)
if scores:
self.fields["axe_%s" % i].initial = scores[int(i)]
self.helper = FormHelper()
self.helper.layout = Layout()
for i in review_fields:
self.helper.layout.fields.append(
InlineRadios("axe_%s" % i)
)
self.helper.layout.fields.append(
ButtonHolder(
Submit('submit', 'Submit', css_class='btn btn-primary')
)
模型
class Review(TimeStampedModel):
""" Review is a model for collecting answers from reviewers """
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False,
)
user = models.ForeignKey(
get_user_model(),
null=False,
on_delete=models.PROTECT)
submission = models.ForeignKey(
Submission,
null=False,
on_delete=models.CASCADE
)
scores = JSONField(null=True, blank=True)
avg_score = models.DecimalField(max_digits=3, decimal_places=2, default=0)
class Meta:
unique_together = ("user", "submission")
ordering = ['-avg_score', '-created']
def save(self, *args, **kwargs):
self.avg_score = self.calc_avg_score()
import pdb; pdb.set_trace()
# save() is called twice and when it runs a second time, it errors because no values are set
super().save(*args, **kwargs)
self.submission.save()
答案
@dirkgroten为我指明了正确的方向。代码解决方案如下-
def test_form_valid_with_object(self):
user = User.objects.create_superuser('foo', 'myemail@test.com', 'bar')
self.review.user = user
self.review.save()
self.submission.conference.reviewers.add(user)
self.client.login(username='foo', password='bar')
response = self.client.post(
reverse('submissions:review_update', kwargs=self.kwargs),
data={'axe_0': '4', 'axe_1': '4', 'axe_2': '4'})
self.assertEqual(302, response.status_code)
答案 0 :(得分:1)
您这样做的方式是错误的。您应该在单独的测试中测试表单和视图。
通过使用data
实例化表单(不使用instance
实例化表单来创建对象)并添加instance
进行对象更新来测试您的表单。检查表格的有效性以获取有效和无效的输入。例如:
form = ReviewForm(data=kwargs, instance=self.submission)
self.assertFalse(form.is_valid())
self.assertTrue(form.errors['some_field']) # check some_field has an error
然后通过向他们提出一个请求并测试响应来测试您的视图:
self.client.force_login(user) # if you test for logged in user
response = self.client.post(url, data={...}) # this runs all your view code
self.assertEqual(302, response.status_code) # form was valid
self.assertTrue(Review.objects.exists())
# or in case of invalid data
self.assertEqual(200, response.status_code)
self.assertTrue(response.context['form'].errors)