【问题标题】:Django Test Client does not create database entriesDjango 测试客户端不创建数据库条目
【发布时间】:2014-07-26 16:40:27
【问题描述】:

我正在使用 Django 的内置测试客户端为我的视图创建单元测试,以创建模拟请求。 我正在调用的视图应该在数据库中创建一个对象。但是,当我从测试方法中查询数据库时,该对象不存在 - 它要么尚未创建,要么在从视图返回时被丢弃。

这是视图:

def apply_to_cmp(request, campaign_id):
    """ Creates a new Application to 'campaign_id' for request.user """
    campaign = Campaign.objects.get(pk = campaign_id)
    if not Application.objects\
                      .filter(campaign = campaign, user = request.user)\
                      .exists():
        application = Application(**{'campaign' : campaign,
                                     'user'     : request.user})
        application.save()

    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

这是调用它的测试:

def test_create_campaign_app(self):
    """ Calls the method apply_to_cmp in .views """
    c = Client()
    c.login(username = self.username, password = self.password)
    url = '/campaign/' + self.campaign.id + '/apply/'
    response = c.get(url)

    # Check whether request was successful (should return 302: redirect)
    self.assertEqual(response.status_code, 302)

    # Verify that an Application object was created
    app_count = Application.objects\
                .filter(user = self.user, campaign = self.campaign)\
                .count()
    self.assertEqual(app_count, 1)

这是运行测试的输出:

Traceback (most recent call last):
  File "/test_views.py", line 40, in test_create_campaign_app
    self.assertEqual(app_count, 1)
AssertionError: 0 != 1

apply_to_cmp 方法肯定被调用,因为response.status_code == 302,但仍然没有创建 Application 对象。我做错了什么?

编辑:解决方案

Client.login 失败,因为登录系统没有在setUp 方法中正确初始化。我通过使用包含登录系统设置的initial_data.json 调用call_command('loaddata', 'initial_data.json') 来解决此问题。此外,HttpResponseRedirect(request.META.get('HTTP_REFERER')) 没有工作,原因很明显。我把那一点改成

if request.META.get('HTTP_REFERER'):
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
return HttpResponse()

因此测试

self.assertEqual(response.status_code, 200)

感谢您的帮助!

【问题讨论】:

    标签: python django unit-testing python-3.x


    【解决方案1】:

    您的代码没有什么特别错误的地方 - 但很明显,您的测试用例或您正在测试的代码没有按照您的想法运行。现在是时候质疑你的假设了。

    The method apply_to_cmp is definitely being called, since response.status_code == 302
    

    这是您的第一个假设,可能不正确。如果您检查响应对象中的其他详细信息,您可能会更好地了解正在发生的事情。例如,检查response.redirect_chain 并确认它实际上重定向到您期望的位置:

    response = c.get(url, follow=True)
    self.assertEqual(response.redirect_chain, [<expected output here>])
    

    其他细节呢?我看不到您提供的代码中定义了 self.username 和 self.password 的位置。您是否 100% 确定您的登录测试代码有效? c.login() 返回 'True' 或 'False' 以指示登录是否成功。在我的测试用例中,我喜欢确认登录成功。

    login_success = c.login(username = self.username, password = self.password)
    self.assertTrue(login_success)
    

    你也可以更笼统一些。如果你检查Application.objects.filter(user=self.user, campaign=self.campaign),你什么也找不到,但是检查Application.objects.all()呢?您知道特定项目不在您的数据库中,但是您知道当时测试代码中存储在数据库中的内容(如果有的话)吗?你期望那里有其他物品吗?检查以确认您的期望是真实的。

    我认为您可以解决这个问题,但您需要在分析测试用例时更加积极,而不仅仅是看到您的 app_count 变量不等于 1。检查您的响应对象,放入一些调试语句,并质疑每一个假设。

    【讨论】:

    • 这让我走上了正轨,我认为 Client.login 如果失败会抛出异常。问题是在setUp 函数中没有正确启动登录系统。当我弄清楚所有细节时会更新。谢谢!
    【解决方案2】:

    首先,如果您从django.test.TestCase 继承,请考虑每个测试都包含在事务中的事实(official docs)。

    然后,您可以将 db 日志记录添加到您的项目中,以查看数据库是否有命中 (official docs)。

    最后确保您在这一行使用正确的查找:filter(user = self.user, campaign = self.campaign)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 2012-07-30
      • 2012-04-20
      相关资源
      最近更新 更多