Django Test Client不会创建数据库条目

时间:2014-06-05 15:35:43

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

我使用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方法中正确初始化。我通过调用带有call_command('loaddata', 'initial_data.json') initial_data.json的{​​{1}}来修复此问题,其中包含登录系统的设置。此外,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)

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

您的代码没有什么特别突出的 - 但显然您的测试用例或您正在测试的代码并不像您想象的那样工作。现在是时候质疑你的假设了。

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()返回&#39; True&#39;或者“假”&#39;表明登录是否成功。在我的测试用例中,我想确认登录成功。

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.检查你的响应对象,输入一些调试语句,并质疑每个假设。

答案 1 :(得分:0)

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

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

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