【问题标题】:Django unit testing if a POST request properly updates a model instanceDjango 单元测试 POST 请求是否正确更新模型实例
【发布时间】:2021-12-09 21:20:51
【问题描述】:

我无法理解为什么我的测试总是失败。

我有两个模型(只显示相关代码):

class Listings(models.Model):
    listing_instagram = models.URLField(null=True, blank=True)
    listing_facebook = models.URLField(null=True, blank=True)
    ...

class ListingsDescription(models.Model):
    listing = models.OneToOneField(Listings, on_delete=models.CASCADE)
    space_description = models.TextField(max_length=1000, blank=True)
    accessibility_description = models.TextField(max_length=1000, blank=True)
    ...

我有一个功能正常的视图,可以处理两种表单(每个模型一个表单):

def some_view(request, listing_id):
    listing = get_object_or_404(Listings, id=listing_id)
    listing_description = listing.listingsdescription

    if request.method == "POST":
        form_a = ListingForm(request.POST or None, instance=listing)
        form_b = ListingDescriptionForm(request.POST or None, instance=listing_description)
        if form_a.is_valid() and form_b.is_valid():
            form_a.save()
            form_b.save()
            messages.success(request, "Changes Made")
            return HttpResponseRedirect(reverse('destination')

在我的浏览器上手动测试工作正常,所有字段都正确保存在数据库中。

但是,运行以下测试:

class ListingJourney(TestCase):
@classmethod
def setUpTestData(cls):
    cls.client = Client()
    # Create Listing
    cls.listing = ...

def listing_post(self):
    self.assertTrue(Listings.objects.filter(id=self.listing.id).exists())
    response = self.client.get(reverse('new_listing', kwargs={'listing_id': self.listing.id}),
                               follow=True)
    self.assertEqual(response.status_code, 200)
    self.assertTemplateUsed(response, template_name='foo/listing.html')

    response = self.client.post(reverse('new_listing', kwargs={'listing_id': self.listing.id}),
                                follow=True,
                                data={
                                    'space_description': "Lorem ipsum dolor",
                                    'neighborhood_description': "Lorem ipsum dolor",
                                    'listing_instagram': "https://www.instagram.com/listing/",
                                    'listing_facebook': "https://www.facebook.com/listing/",
                                    # some more data
                                })
    self.assertRedirects(response, reverse('redirect', kwargs={'listing_id': self.listing.id}),
                         status_code=302,
                         target_status_code=200,
                         fetch_redirect_response=True)
    self.assertEqual(self.listing.listingsdescription.space_description, "Lorem ipsum dolor")
    self.assertEqual(self.listing.listing_facebook, "https://www.facebook.com/listing/")
    self.assertEqual(self.listing.listing_instagram, "https://www.instagram.com/listing/")

测试失败:

self.assertEqual(self.listing.listing_facebook, "https://www.facebook.com/listing/")

Traceback (most recent call last):
  File "...\tests.py", line 153, in listing_post
    self.assertEqual(self.listing.listing_facebook, "https://www.facebook.com/listing/")
AssertionError: None != 'https://www.facebook.com/listing/'

这意味着描述字段已正确保存并带有正确的文本,但社交媒体字段仍为空。再次手动测试,一切正常。

在视图中打印request.POST,并手动测试,也显示键名是正确的:

<QueryDict: {'csrfmiddlewaretoken': ['blabla'], 
'listing_instagram': ['https://www.instagram.com/listing/'],
'listing_facebook': ['https://www.facebook.com/listing/'],
'space_description': ['Lorem ipsum dolor'], 
'neighborhood_description': ['Lorem ipsum dolor']}>

可能是因为数据库在断言数据已正确保存之前还没有完成模型字段的保存?

感谢您的帮助。

【问题讨论】:

  • 看起来您正在尝试使用相同的 pk 创建一个新列表,但这是行不通的。
  • @michjnich 我只是在使用 setUpTestData 创建一个新列表,而不是在实际测试中。正如您在视图中看到的那样,POST 请求也只是更新现有的列表对象。

标签: django unit-testing django-testing


【解决方案1】:

我通过在 POST 请求后对列表对象调用 refresh_from_db() 解决了这个问题。

response = self.client.post(reverse('new_listing', kwargs={'listing_id': self.listing.id}),
                            follow=True,
                            data={
                                'space_description': "Lorem ipsum dolor",
                                'neighborhood_description': "Lorem ipsum dolor",
                                'listing_instagram': "https://www.instagram.com/listing/",
                                'listing_facebook': "https://www.facebook.com/listing/",
                                # some more data
                            })
self.assertRedirects(response, reverse('redirect', kwargs={'listing_id': self.listing.id}),
                     status_code=302,
                     target_status_code=200,
                     fetch_redirect_response=True)


# Added this:
self.listing.refresh_from_db()

self.assertEqual(self.listing.listingsdescription.space_description, "Lorem ipsum dolor")
self.assertEqual(self.listing.listing_facebook, "https://www.facebook.com/listing/")
self.assertEqual(self.listing.listing_instagram, "https://www.instagram.com/listing/")

我仍然很困惑,为什么listing.space_description 的测试结果是肯定的,而instagram 和facebook 的结果却不是。如果有人能解释原因,那就太棒了。

【讨论】:

    猜你喜欢
    • 2017-05-01
    • 2018-04-26
    • 1970-01-01
    • 1970-01-01
    • 2017-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    相关资源
    最近更新 更多