問題
更新@login_required
: この問題は、デコレータとはほとんど関係がないことが判明しました!
で装飾されたビューをテストしようとすると、厄介な動作が発生し@login_required
ます。
@login_required
(パスワード変更ビュー)で装飾されたビューに実際に移動できるテストが 1 つあります。ただし、別のテストは常にログインにリダイレクトされます。どのように書き直そうとしても、ユーザーをログインさせて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 に固有のものであるか、この場合は役に立ちませんでした (たとえば、こちらを参照)。
解決策 (2 つの適切な回答を組み合わせる)
この質問に対して 2 つの非常に良い回答を受け取りました。どちらも、私が投稿したスニペットの重要な見落としを浮き彫りにしました。この問題は@login_required
の動作とは関係がなく、(a) ユーザーへの署名が間違っていること、および (b) ユーザー認証のチェックが間違っていることにすべて関係していました。
どの回答を受け入れるかを決めるのに苦労しましたが、少し考えた後、Konrad Hałas の回答を受け入れることにしました。これは、予期せぬ行動の原因である私の側の重大な見落としを正確に示しているからです。
とはいえ、故障したテスト ラインを使用していなければ、もっと早くこれに気がついたでしょうself.assertTrue(user.is_authenticated())
。解決策が実際には 2 つの部分であったことを強調するために、問題のあるコードを修正するための 2 つの手順を次に示します。
# 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 の情報を参照してください。したがって、このコードを修正するステップ 2 は次のとおりです。
# 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())