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

dri*_*her 8 python testing django unit-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')
Run Code Online (Sandbox Code Playgroud)

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

我可以确认这种行为没有反映在应用程序的"正常"功能中; 当我实际运行服务器然后导航到此视图时,装饰器的工作方式完全正常(即,它允许在登录时访问,并重定向到登录视图).

使用Django 1.3.1.我正在使用来自django-nose的testrunner,但我可以确认无论我使用哪个testrunner都会发生这个问题.

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

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

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

我很难选择接受哪个答案,但经过一番思考后,我决定接受KonradHał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
Run Code Online (Sandbox Code Playgroud)

断言行仍然有问题,因为有效用户总是满足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)
Run Code Online (Sandbox Code Playgroud)

最后,如果您需要测试您的用户是否在使用的情况下登录client.login(即测试登录表单),这应该可行:

self.assertTrue(response.context['user'].is_authenticated())
Run Code Online (Sandbox Code Playgroud)

Kon*_*łas 8

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

self.client.login(username=user.username, password='<user password>')
Run Code Online (Sandbox Code Playgroud)

  • 是的,你做不到.小OT:也许试试[factory_boy](https://github.com/dnerdy/factory_boy#customizing-creation) - 这是更好的解决方案然后django fixtures.这里有一个示例如何[处理用户密码](https://gist.github.com/3504037) (2认同)