0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PasswordResetConfirmViewのテスト

Posted at

目的

今回パスワード忘れた時の再設定機能に使うviewのテストを作りました。
と言ってもDjangoには既にPasswordResetConfirmViewがあり、
ほとんど自前で書くところはなかったので、getとpost時の挙動だけを確認します。

甘く見ていたら意外と詰まるところが多かったです。

テスト対象のview

# views.py
class PasswordResetConfirm(PasswordResetConfirmView):
    form_class = MySetPasswordForm
    template_name = 'users/password_reset_confirm.html'
    success_url = reverse_lazy('users:password_reset_complete')

MySetPasswordFormはDjangoのSetPasswordFormをBootstrapに対応しただけの
form。

テスト

Getのテスト

class PasswordResetConfirm(TestCase):
    """パスワード再入力viewのテスト"""
    def setUp(self):
        """ユーザーを登録し、uidとtokenを準備"""
        from django.contrib.auth import get_user_model
        User = get_user_model()
        user = User.objects.create_user(
            email='test@test.com',
            password='test_password',
        )
        user.save()

        self.uid = urlsafe_base64_encode(force_bytes(user.pk))
        self.token = default_token_generator.make_token(user)

    def test_get(self):
        """getリクエスト"""
        url = reverse(
            'users:password_reset_confirm',
            kwargs={
                'uidb64': self.uid,
                'token': self.token,
            }
        )
        response = self.client.get(url)
        
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response,'users/password_reset_confirm.html')

上記はステータスのAssertionErrorが起きてしまいます。
理由は、PasswordResetConfirmViewの内部でtokenをset-passwordに変えてリダイレクトしてるからです。

修正後のテストコード。


class PasswordResetConfirm(TestCase):
    """パスワード再入力viewのテスト"""
    def setUp(self):
        """ユーザーを登録し、uidとtokenを準備"""
        from django.contrib.auth import get_user_model
        User = get_user_model()
        user = User.objects.create_user(
            email='test@test.com',
            password='test_password',
        )
        user.save()

        self.uid = urlsafe_base64_encode(force_bytes(user.pk))
        self.token = default_token_generator.make_token(user)

    def test_get(self):
        """getリクエスト"""
        url = reverse(
            'users:password_reset_confirm',
            kwargs={
                'uidb64': self.uid,
                'token': self.token,
            }
        )
        response = self.client.get(url)

        # getリクエスト時、
        # token部分をset-passwordに置き換えて
        # リダイレクトされることの確認
        # ステータス302
        self.assertEqual(response.status_code, 302)
        # リダイレクトpassword_reset_confirm.html
        redirect_url = reverse(
            'users:password_reset_confirm',
            kwargs={
                'uidb64': self.uid,
                'token': 'set-password',
            }
        )
        self.assertRedirects(
            response,
            redirect_url
        )

Postのテスト

class PasswordResetConfirm(TestCase):
    """パスワード再入力viewのテスト"""
    # setUp()
    # test_get()

    def test_post(self):
        """postリクエスト"""

        data = {
            'password1': 'test_password2',
            'password2': 'test_password2',
        }
        post_url = reverse(
            'users:password_reset_confirm',
            kwargs={
                'uidb64': self.uid,
                'token': 'set-password',
            }
        )
        response = self.client.post(post_url, data=data)

        self.assertEqual(response.status_code, 302)
        self.assertRedirects(
            response,
            reverse('users:password_reset_complete')
        )

上記もまたAssertionErrorが起きてしまいます。
理由は最初のget時にトークンをセッションに保存しているためで、
このテストはいきなりpostしてしまっているからです。

# 修正後
class PasswordResetConfirm(TestCase):
    """パスワード再入力viewのテスト"""
    # setUp()
    # test_get()

    def test_post(self):
        """postリクエスト"""

        # PasswordResetConfirmViewはget時にトークンをsessionに保存し、
        # post時にsessionのトークンをチェックしているため
        # 初めにgetリクエストを投げる
        get_url = reverse(
            'users:password_reset_confirm',
            kwargs={
                'uidb64': self.uid,
                'token': self.token,
            }
        )
        self.client.get(get_url)

        # 次にpostを投げる
        data = {
            'password1': 'test_password2',
            'password2': 'test_password2',
        }
        post_url = reverse(
            'users:password_reset_confirm',
            kwargs={
                'uidb64': self.uid,
                'token': 'set-password',
            }
        )
        response = self.client.post(post_url, data=data)

        self.assertEqual(response.status_code, 302)
        self.assertRedirects(
            response,
            reverse('users:password_reset_complete')
        )

まだAssertionErrorが起きてしまいます。
今回はpostで送るデータが問題で、SetPasswordFormのフィールドは
password1 ではなく、new_password1 を使っています。

修正後のテストコードが以下です。


# 2度目の修正後
class PasswordResetConfirm(TestCase):
    """パスワード再入力viewのテスト"""
    # setUp()
    # test_get()

    def test_post(self):
        """postリクエスト"""

        # PasswordResetConfirmViewはget時にトークンをsessionに保存し、
        # post時にsessionのトークンをチェックしているため
        # 初めにgetリクエストを投げる
        get_url = reverse(
            'users:password_reset_confirm',
            kwargs={
                'uidb64': self.uid,
                'token': self.token,
            }
        )
        self.client.get(get_url)

        # 次にpostを投げる
        data = {
            'new_password1': 'test_password2',
            'new_password2': 'test_password2',
        }
        post_url = reverse(
            'users:password_reset_confirm',
            kwargs={
                'uidb64': self.uid,
                'token': 'set-password',
            }
        )
        response = self.client.post(post_url, data=data)

        self.assertEqual(response.status_code, 302)
        self.assertRedirects(
            response,
            reverse('users:password_reset_complete')
        )

これでやっと、getとpostが期待通りに動くことの確認ができました。

まとめ

Djangoに頼りすぎて、テストが全然かけていなかったですが、
Djangoの実際のソースコードを見ることが多く、良い経験になりましたし、
すごい重要だということが今回分かりました。

今回のアプリ作成で初めてテストを書き始めたので、
そもそもテストの仕方が良くないところがあると思いますが、
自分と同じようにPasswordResetConfirmViewのテストをしたい方の参考になれば幸いです。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?