質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Q&A

解決済

1回答

1102閲覧

Djangoのユニットテストでのリダイレクト検証で、AssertionError: 301となる

deango

総合スコア161

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

0グッド

0クリップ

投稿2022/09/09 18:39

前提

DjangoでSNSアプリを作成しています。
基本機能の日記のCRUⅮのユニットテストをしていますが、
一部のリダイレクト検証で、AssertionError: 301となります。

djangoのドキュメントなど確認しましたが、301となるケースの情報がなく、
ご教示いただけますと幸いです。

書籍「動かして学ぶ!Python Django開発入門」のコードを参考にしています。

実現したいこと

リダイレクト検証の成功

発生している問題・エラーメッセージ

エラーメッセージ ====================================================================== FAIL: test_create_diary_success (diary.tests.test_views.TestDiaryCreateView) 日記作成処理が成功することを検証する ---------------------------------------------------------------------- Traceback (most recent call last): File "c:\WORK\python\venv_nyapu\nyapu_pj\diary\tests\test_views.py", line 73, in test_create_diary_success self.assertRedirects(response, reverse_lazy('diary:diary_list', kwargs={'username': self.test_user})) File "C:\WORK\python\venv_nyapu\lib\site-packages\django\test\testcases.py", line 335, in assertRedirects self.assertEqual( AssertionError: 301 != 302 : Initial response didn't redirect as expected: Response code was 301 (expected 302) ====================================================================== FAIL: test_delete_diary_success (diary.tests.test_views.TestDiaryDeleteView) 日記削除処理が成功することを検証する ---------------------------------------------------------------------- Traceback (most recent call last): File "c:\WORK\python\venv_nyapu\nyapu_pj\diary\tests\test_views.py", line 163, in test_delete_diary_success self.assertRedirects(response, reverse_lazy('diary:diary_list')) File "C:\WORK\python\venv_nyapu\lib\site-packages\django\test\testcases.py", line 335, in assertRedirects self.assertEqual( AssertionError: 301 != 302 : Initial response didn't redirect as expected: Response code was 301 (expected 302) ====================================================================== FAIL: test_update_diary_success (diary.tests.test_views.TestDiaryUpdateView) 日記編集処理が成功することを検証する ---------------------------------------------------------------------- Traceback (most recent call last): File "c:\WORK\python\venv_nyapu\nyapu_pj\diary\tests\test_views.py", line 119, in test_update_diary_success self.assertRedirects(response, reverse_lazy('diary:diary_detail', kwargs={'pk': diary.pk})) File "C:\WORK\python\venv_nyapu\lib\site-packages\django\test\testcases.py", line 335, in assertRedirects self.assertEqual( AssertionError: 301 != 302 : Initial response didn't redirect as expected: Response code was 301 (expected 302)

該当のソースコード

test_view.py

1import io 2 3from django.contrib.auth import get_user_model 4from django.test import TestCase, Client 5from django.urls import reverse_lazy, reverse 6 7from PIL import Image 8from django.core.files.uploadedfile import SimpleUploadedFile 9 10from ..models import Diary 11from django.contrib import auth 12 13class LoggedInTestCase(TestCase): 14 """各テストクラスで共通の事前準備処理をオーバライドした独自TestCaseクラス""" 15 16 def setUp(self): 17 """テストメソッド実行前の事前設定""" 18 19 # テストユーザーのパスワード 20 self.password = 'only3100nyapu' 21 22 # 各インスタンスメソッドで使うテスト用ユーザを生成し 23 # インスタンス変数に格納しておく 24 self.test_user = get_user_model().objects.create_user( 25 username='unittestonly1', 26 email='unittestonly1@example.com', 27 password=self.password) 28 29 # テスト用ユーザーでログインする 30 self.client.login(username=self.test_user.username, password=self.password) 31 32 # ログイン状態か確認 33 self.assertTrue( 34 auth.get_user(self.client).is_authenticated 35 ) 36 37 38class TestDiaryCreateView(LoggedInTestCase): 39 """DiaryCreateView用のテストクラス""" 40 41 def _make_dummy_image(self): 42 """テスト用の画像ファイルをPILで作成""" 43 file_obj = io.BytesIO() 44 im = Image.new('RGBA', size=(10, 10), color=(256, 0, 0)) 45 im.save(file_obj, 'png') 46 file_obj.name = 'test.png' 47 file_obj.seek(0) 48 return file_obj 49 50 def test_create_diary_success(self): 51 """日記作成処理が成功することを検証する""" 52 53 # テスト用の画像ファイル 54 img = self._make_dummy_image() 55 56 # Postパラメータ 57 params = {'title': 'テストタイトル', 58 'content': '本文', 59 'photo1': SimpleUploadedFile( 60 img.name, 61 img.read(), 62 content_type='image/png',), 63 'photo2': '', 64 'photo3': '', 65 'lat': 35.709, 66 'lon': 139.7319, 67 } 68 69 # 新規日記作成処理(Post)を実行 70 response = self.client.post(reverse_lazy('diary:diary_create'), params, follow=True) 71 72 # 日記リストページへのリダイレクトを検証 73 self.assertRedirects(response, reverse_lazy('diary:diary_list', kwargs={'username': self.test_user})) 74 75 # 日記データがDBに登録されたかを検証 76 self.assertEqual(Diary.objects.filter(title='テストタイトル').count(), 1) 77 78 def test_create_diary_failure(self): 79 """新規日記作成処理が失敗することを確認する""" 80 81 # 新規日記作成処理(Post)を実行 82 response = self.client.post(reverse_lazy('diary:diary_create')) 83 84 # 必須フォームフィールドが未入力によりエラーになることを検証 85 self.assertFormError(response, 'form', 'photo1', 'このフィールドは必須です。') 86 87 88class TestDiaryUpdateView(LoggedInTestCase): 89 """DiaryUpdateView用のテストクラス""" 90 91 def _make_dummy_image(self): 92 """テスト用の画像ファイルをPILで作成""" 93 file_obj = io.BytesIO() 94 im = Image.new('RGBA', size=(10, 10), color=(256, 0, 0)) 95 im.save(file_obj, 'png') 96 file_obj.name = 'test.png' 97 file_obj.seek(0) 98 return file_obj 99 100 def test_update_diary_success(self): 101 """日記編集処理が成功することを検証する""" 102 103 # テスト用の画像ファイル 104 img = self._make_dummy_image() 105 106 # テスト用日記データの作成 107 diary = Diary.objects.create(user=self.test_user, title="タイトル編集後", photo1=SimpleUploadedFile( 108 img.name, 109 img.read(), 110 content_type='image/png', )) 111 112 # Postパラメータ 113 params = {'title': 'タイトル編集後'} 114 115 # 日記編集処理(Post)を実行 116 response = self.client.post(reverse_lazy('diary:diary_update', kwargs={'pk': diary.pk}), params, follow=True) 117 118 # 日記詳細ページへのリダイレクトを検証 119 self.assertRedirects(response, reverse_lazy('diary:diary_detail', kwargs={'pk': diary.pk})) 120 121 # 日記データが編集されたかを検証 122 self.assertEqual(Diary.objects.get(pk=diary.pk).title, 'タイトル編集後') 123 124 125 def test_update_diary_failure(self): 126 """日記編集処理が失敗することを検証する""" 127 128 # 日記編集処理(Post)を実行 129 response = self.client.post(reverse_lazy('diary:diary_update', kwargs={'pk': 999}), follow=True) 130 131 # 存在しない日記データを編集しようとしてエラーになることを検証 132 self.assertEqual(response.status_code, 404) 133 134 135class TestDiaryDeleteView(LoggedInTestCase): 136 """DiaryDeleteView用のテストクラス""" 137 138 def _make_dummy_image(self): 139 """テスト用の画像ファイルをPILで作成""" 140 file_obj = io.BytesIO() 141 im = Image.new('RGBA', size=(10, 10), color=(256, 0, 0)) 142 im.save(file_obj, 'png') 143 file_obj.name = 'test.png' 144 file_obj.seek(0) 145 return file_obj 146 147 def test_delete_diary_success(self): 148 """日記削除処理が成功することを検証する""" 149 150 # テスト用の画像ファイル 151 img = self._make_dummy_image() 152 153 # テスト用日記データの作成 154 diary = Diary.objects.create(user=self.test_user, title='タイトル', photo1=SimpleUploadedFile( 155 img.name, 156 img.read(), 157 content_type='image/png', )) 158 159 # 日記削除処理(Post)を実行 160 response = self.client.post(reverse_lazy('diary:diary_delete', kwargs={'pk': diary.pk}), follow=True) 161 162 # 日記リストページへのリダイレクトを検証 163 self.assertRedirects(response, reverse_lazy('diary:diary_list')) 164 165 # 日記データが削除されたかを検証 166 self.assertEqual(Diary.objects.filter(pk=diary.pk).count(), 0) 167 168 def test_delete_diary_failure(self): 169 """日記削除処理が失敗することを検証する""" 170 171 # 日記削除処理(Post)を実行 172 response = self.client.post(reverse_lazy('diary:diary_delete', kwargs={'pk': 999}), follow=True) 173 174 # 存在しない日記データを削除しようとしてエラーになることを検証 175 self.assertEqual(response.status_code, 404) 176

views.py

1importは略します。 2 3class DiaryCreateView(LoginRequiredMixin, generic.CreateView): 4 model = Diary 5 template_name = 'diary_create.html' 6 form_class = DiaryCreateForm 7 8 def get_success_url(self): 9 return reverse_lazy('diary:diary_list', kwargs={'username': self.request.user}) 10 11 def form_valid(self, form): 12 diary = form.save(commit=False) 13 diary.user = self.request.user 14 diary.save() 15 messages.success(self.request, '日記を作成しました。') 16 return super().form_valid(form) 17 18 def form_invalid(self, form): 19 messages.error(self.request, "日記の作成に失敗しました。") 20 return super().form_invalid(form) 21 22 23class DiaryUpdateView(LoginRequiredMixin, generic.UpdateView): 24 model = Diary 25 template_name = 'diary_update.html' 26 form_class = DiaryCreateForm 27 28 def get_success_url(self): 29 return reverse_lazy('diary:diary_detail', kwargs={'pk': self.kwargs['pk']}) 30 31 def form_valid(self, form): 32 messages.success(self.request, '日記を更新しました。') 33 return super().form_valid(form) 34 35 def form_invalid(self, form): 36 messages.error(self.request, "日記の更新に失敗しました。") 37 return super().form_invalid(form) 38 39 40class DiaryDeleteView(LoginRequiredMixin, generic.DeleteView): 41 model = Diary 42 template_name = 'diary_delete.html' 43 44 def get_success_url(self): 45 return reverse_lazy('diary:diary_list', kwargs={'username': self.request.user}) 46 47 def test_func(self, **kwargs): 48 pk = self.kwargs["pk"] 49 diary = Diary.objects.get(pk=pk) 50 return (diary.user == self.request.user) 51 52 def delete(self, request, *args, **kwargs): 53 messages.success(self.request, "日記を削除しました。") 54 return super().delete(request, args, **kwargs) 55

試したこと

テストユーザでのログインは確認でき、
日記の削除、編集の失敗ケースの処理は検証成功しています。

日記の削除、編集の失敗ケースでもAssertionError: 301になっていたのですが、
self.client.postにfollow=Trueを追加することででなくなりました。

日記の作成、削除、編集の成功ケースにもfollow=Trueを追加しましたが、こちらは効果なしでした。

補足情報(FW/ツールのバージョンなど)

Python 3.10.6
Django 4.0.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

settings.pyで以下のSSLリダイレクトを行っていたことが原因でした。
SECURE_SSL_REDIRECT = True

こちらをコメントアウトで解消しました。

投稿2022/09/11 15:49

deango

総合スコア161

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問