Django - 测试 - @login_required装饰器的问题

时间:2012-08-28 19:52:58

标签: python django unit-testing testing django-authentication

问题

更新:事实证明,这个问题与@login_required装饰器没什么关系!

当我尝试测试用@login_required修饰的视图时,我会遇到挑剔的行为。

我有一个实际上可以转到用@login_required修饰的视图的测试(密码更改视图)。但是,不同的测试总是被重定向到登录。无论我尝试重写它的哪种方式,它都不会让我的测试用户通过,即使我正在记录用户并事先断言user.is_authenticated()

以下是有问题的相关测试片段:

# Log user in
self.client.login(username=user.username, password=user.password)
self.assertTrue(user.is_authenticated())

# Go to account_edit view
url = reverse('account_edit')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'users/account_edit_form.html')

这不可避免地会重定向到登录视图,就好像用户没有登录一样。

我可以确认此行为未反映在应用的“正常”功能中;当我实际运行服务器然后导航到此视图时,装饰器完全按预期工作(即,它允许登录时访问,并重定向到登录视图)。

使用Django 1.3.1。我正在使用django-nose的测试人员,但我可以确认无论我使用哪个测试人员都会发生这个问题。

此外,我发现了之前的几个问题,但建议的解决方案要么特别适用于旧版本的Django,要么在这种情况下没有帮助(例如,请参阅here)。

解决方案(结合两个好的答案)

我收到了两个非常好的答案,这两个问题突出了我发布的片段中的重要疏忽。该问题与@login_required的行为无关,而且与(a)错误地签署用户以及(b)检查用户身份验证错误有关。

我很难选择接受哪个答案,但经过一番思考后,我决定接受KonradHałas的答案,因为它确定了我的关键疏忽,这是意外行为的根源。 / p>

尽管如此,如果我没有使用错误的测试线self.assertTrue(user.is_authenticated()),我会更快地想出来。因此,要强调解决方案实际上是两个部分,这里是修复有问题代码的两个步骤:

# Log user in *NOTE: Password needs to be raw (from Konrad's answer)
self.client.login(username=user.username, password="pass")
self.assertTrue(user.is_authenticated()) # <-- still not correct

断言行仍然有问题,因为有效用户始终满足user.is_authenticated()。有关此问题的解释,请参阅Alasdair的信息。因此,修复此代码的第二步是:

# Log user in *NOTE: Password needs to be raw (from Konrad's answer)
login_successful = self.client.login(username=user.username, password="pass")
self.assertTrue(login_successful) # Much better! (see Alasdair's answer)

最后,如果你需要测试你的用户是否使用client.login 登录(即测试登录表单),这应该有效:

self.assertTrue(response.context['user'].is_authenticated())

2 个答案:

答案 0 :(得分:8)

user.password是密码哈希。您无法使用它登录。您需要使用原始密码:

self.client.login(username=user.username, password='<user password>')

答案 1 :(得分:3)

这里的问题是,is_authenticated方法总是True实例返回User

在模板或视图中,它可能很有用 - 如果request.user.is_authenticated()True,那么您拥有真实用户,而不是AnonymousUser,并且可以相应地进行操作。但是,如果您开始使用User对象,那么is_authenticated()可能会让您感到困惑!

您可以检查测试客户端的login()方法的返回值,以测试它是否成功。

login_successful = c.login(username='fred', password='secret')
self.assertTrue(login_successful)