djangoの login_required を使ったメソッドのテストを作成している時に、一工夫必要だったので紹介します。
login_requiredとはログインをしていないユーザーが閲覧できないようにビュー関数に設定するDjangoのデコレーターです。ログインが成功すると、閲覧しようとしていたページにリダイレクトしてくれます。
一般的なリダイレクトテスト
ログインページにリダイレクするかをテストしたかったので最初は以下のように書きました。
from django.conf import settings
from django.test import TestCase
from django.urls import reverse
class TestLoginRequired(TestCase):
def test_login_required(self):
response = self.client.get('http://example.com/admin/')
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, reverse(settings.LOGIN_URL))
DjangoにはTestCaseというテスト向けのクラスがあり、リダイレクトのテストでは、このクラスのself.assertRedirects()メソッドを使う方法が一般的です。
しかし、login_required()を使ったビュー関数のテストでは失敗します。
self.assertRedirects()でurlの同一性の確認をしていますが、responseのurlは /admin/login/?next=%2F ~ のようにクエリストリング(?next=から始まる文字列)が追加されているのに対し、reverse(settings.LOGIN_URL)は /admin/login/ になります。
注) settings.LOGIN_URLのurlを/admin/login/に設定している前提です。
self.assertRedirects()ではクエリ文字の同一性もチェックする仕様になっているため失敗しました。
解決策
ログインページにリダイレクトしているかをテストしたいので、クエリストリング以外が同一であれば十分です。
今回は、response.urlの文字列が、reverse(settings.LOGIN_URL)から始まる文字列であるかを確認する事で解決しました。
from django.conf import settings
from django.test import TestCase
from django.urls import reverse
class TestLoginRequired(TestCase):
def test_login_required(self):
response = self.client.get('http://example.com/admin/')
self.assertEqual(res.status_code, 302)
self.assertTrue(response.url.startswith(reverse(settings.LOGIN_URL)))
response.urlはstr型なので、str型のstartswithメソッドを使って先頭文字が同一かどうかを判定しています。