8

问题

更新@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 的 testrunner,但我可以确认无论我使用哪个 testrunner,都会发生此问题。

另外,我发现了几个以前的问题,但建议的解决方案要么是特定于旧版本的 Django,要么在这种情况下没有帮助(例如,请参见此处)。

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

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

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

尽管如此,如果我没有使用有故障的测试线,我会更快地发现这一点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())
4

2 回答 2

8

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

self.client.login(username=user.username, password='<user password>')
于 2012-08-28T19:57:51.370 回答
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)
于 2012-08-28T20:36:36.647 回答