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

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

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

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

解決済

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

deango
deango

総合スコア160

Django

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

1回答

0リアクション

0クリップ

224閲覧

投稿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

import io from django.contrib.auth import get_user_model from django.test import TestCase, Client from django.urls import reverse_lazy, reverse from PIL import Image from django.core.files.uploadedfile import SimpleUploadedFile from ..models import Diary from django.contrib import auth class LoggedInTestCase(TestCase): """各テストクラスで共通の事前準備処理をオーバライドした独自TestCaseクラス""" def setUp(self): """テストメソッド実行前の事前設定""" # テストユーザーのパスワード self.password = 'only3100nyapu' # 各インスタンスメソッドで使うテスト用ユーザを生成し # インスタンス変数に格納しておく self.test_user = get_user_model().objects.create_user( username='unittestonly1', email='unittestonly1@example.com', password=self.password) # テスト用ユーザーでログインする self.client.login(username=self.test_user.username, password=self.password) # ログイン状態か確認 self.assertTrue( auth.get_user(self.client).is_authenticated ) class TestDiaryCreateView(LoggedInTestCase): """DiaryCreateView用のテストクラス""" def _make_dummy_image(self): """テスト用の画像ファイルをPILで作成""" file_obj = io.BytesIO() im = Image.new('RGBA', size=(10, 10), color=(256, 0, 0)) im.save(file_obj, 'png') file_obj.name = 'test.png' file_obj.seek(0) return file_obj def test_create_diary_success(self): """日記作成処理が成功することを検証する""" # テスト用の画像ファイル img = self._make_dummy_image() # Postパラメータ params = {'title': 'テストタイトル', 'content': '本文', 'photo1': SimpleUploadedFile( img.name, img.read(), content_type='image/png',), 'photo2': '', 'photo3': '', 'lat': 35.709, 'lon': 139.7319, } # 新規日記作成処理(Post)を実行 response = self.client.post(reverse_lazy('diary:diary_create'), params, follow=True) # 日記リストページへのリダイレクトを検証 self.assertRedirects(response, reverse_lazy('diary:diary_list', kwargs={'username': self.test_user})) # 日記データがDBに登録されたかを検証 self.assertEqual(Diary.objects.filter(title='テストタイトル').count(), 1) def test_create_diary_failure(self): """新規日記作成処理が失敗することを確認する""" # 新規日記作成処理(Post)を実行 response = self.client.post(reverse_lazy('diary:diary_create')) # 必須フォームフィールドが未入力によりエラーになることを検証 self.assertFormError(response, 'form', 'photo1', 'このフィールドは必須です。') class TestDiaryUpdateView(LoggedInTestCase): """DiaryUpdateView用のテストクラス""" def _make_dummy_image(self): """テスト用の画像ファイルをPILで作成""" file_obj = io.BytesIO() im = Image.new('RGBA', size=(10, 10), color=(256, 0, 0)) im.save(file_obj, 'png') file_obj.name = 'test.png' file_obj.seek(0) return file_obj def test_update_diary_success(self): """日記編集処理が成功することを検証する""" # テスト用の画像ファイル img = self._make_dummy_image() # テスト用日記データの作成 diary = Diary.objects.create(user=self.test_user, title="タイトル編集後", photo1=SimpleUploadedFile( img.name, img.read(), content_type='image/png', )) # Postパラメータ params = {'title': 'タイトル編集後'} # 日記編集処理(Post)を実行 response = self.client.post(reverse_lazy('diary:diary_update', kwargs={'pk': diary.pk}), params, follow=True) # 日記詳細ページへのリダイレクトを検証 self.assertRedirects(response, reverse_lazy('diary:diary_detail', kwargs={'pk': diary.pk})) # 日記データが編集されたかを検証 self.assertEqual(Diary.objects.get(pk=diary.pk).title, 'タイトル編集後') def test_update_diary_failure(self): """日記編集処理が失敗することを検証する""" # 日記編集処理(Post)を実行 response = self.client.post(reverse_lazy('diary:diary_update', kwargs={'pk': 999}), follow=True) # 存在しない日記データを編集しようとしてエラーになることを検証 self.assertEqual(response.status_code, 404) class TestDiaryDeleteView(LoggedInTestCase): """DiaryDeleteView用のテストクラス""" def _make_dummy_image(self): """テスト用の画像ファイルをPILで作成""" file_obj = io.BytesIO() im = Image.new('RGBA', size=(10, 10), color=(256, 0, 0)) im.save(file_obj, 'png') file_obj.name = 'test.png' file_obj.seek(0) return file_obj def test_delete_diary_success(self): """日記削除処理が成功することを検証する""" # テスト用の画像ファイル img = self._make_dummy_image() # テスト用日記データの作成 diary = Diary.objects.create(user=self.test_user, title='タイトル', photo1=SimpleUploadedFile( img.name, img.read(), content_type='image/png', )) # 日記削除処理(Post)を実行 response = self.client.post(reverse_lazy('diary:diary_delete', kwargs={'pk': diary.pk}), follow=True) # 日記リストページへのリダイレクトを検証 self.assertRedirects(response, reverse_lazy('diary:diary_list')) # 日記データが削除されたかを検証 self.assertEqual(Diary.objects.filter(pk=diary.pk).count(), 0) def test_delete_diary_failure(self): """日記削除処理が失敗することを検証する""" # 日記削除処理(Post)を実行 response = self.client.post(reverse_lazy('diary:diary_delete', kwargs={'pk': 999}), follow=True) # 存在しない日記データを削除しようとしてエラーになることを検証 self.assertEqual(response.status_code, 404)

views.py

importは略します。 class DiaryCreateView(LoginRequiredMixin, generic.CreateView): model = Diary template_name = 'diary_create.html' form_class = DiaryCreateForm def get_success_url(self): return reverse_lazy('diary:diary_list', kwargs={'username': self.request.user}) def form_valid(self, form): diary = form.save(commit=False) diary.user = self.request.user diary.save() messages.success(self.request, '日記を作成しました。') return super().form_valid(form) def form_invalid(self, form): messages.error(self.request, "日記の作成に失敗しました。") return super().form_invalid(form) class DiaryUpdateView(LoginRequiredMixin, generic.UpdateView): model = Diary template_name = 'diary_update.html' form_class = DiaryCreateForm def get_success_url(self): return reverse_lazy('diary:diary_detail', kwargs={'pk': self.kwargs['pk']}) def form_valid(self, form): messages.success(self.request, '日記を更新しました。') return super().form_valid(form) def form_invalid(self, form): messages.error(self.request, "日記の更新に失敗しました。") return super().form_invalid(form) class DiaryDeleteView(LoginRequiredMixin, generic.DeleteView): model = Diary template_name = 'diary_delete.html' def get_success_url(self): return reverse_lazy('diary:diary_list', kwargs={'username': self.request.user}) def test_func(self, **kwargs): pk = self.kwargs["pk"] diary = Diary.objects.get(pk=pk) return (diary.user == self.request.user) def delete(self, request, *args, **kwargs): messages.success(self.request, "日記を削除しました。") return super().delete(request, args, **kwargs)

試したこと

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

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

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

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

Python 3.10.6
Django 4.0.2

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Django

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