POST to TestUpdateView обновляет существующий объект и создает новый объект - PullRequest
0 голосов
/ 05 июня 2019

У меня есть тест для UpdateView, который:

  • Обновление существующего объекта
  • Затем попытка создать новый пустой объект в то же время

Такое поведение не происходит, когда я запускаю представление в браузере, поэтому это как-то связано с тем, как проходит тест.

  • POST для URL обновления
  • Запрос выполняется через UpdateView
  • Form_valid () запускается и нажимает 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)

1 Ответ

1 голос
/ 05 июня 2019

Вы делаете это неправильно.Вы должны проверить свою форму и представления в отдельных тестах.

Проверьте свою форму, создав ее экземпляр с помощью 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)
...