Django测试客户端不创建数据库条目
我正在为我的视图创建单元测试,使用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
,但应用对象仍然没有被创建。我到底做错了什么呢?
3 个回答
Client.login
失败了,因为在 setUp
方法中登录系统没有正确初始化。我通过调用 call_command('loaddata', 'initial_data.json')
来解决这个问题,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)
这个回答是作为对问题的 编辑 发布的,问题是 Django 测试客户端没有创建数据库条目,由 OP kreld 发布,采用 CC BY-SA 3.0 许可。
你的代码看起来没有明显的问题,但很明显,要么是你的测试用例有问题,要么是你测试的代码没有按你想的那样工作。现在是时候重新审视你的假设了。
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 是在哪里定义的。你确定你的登录测试代码是成功的吗?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。仔细检查你的响应对象,添加一些调试语句,质疑每一个假设。