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

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

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

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

テスト駆動開発

テスト駆動開発は、 プログラム開発手法の一種で、 プログラムに必要な各機能をテストとして書き、 そのテストが動作する必要最低限な実装を行い コードを洗練させる、といったサイクルを繰り返す手法の事です。

Q&A

解決済

3回答

2812閲覧

Laravelでユーザー新規登録のテストが通りません。助けてください。

gasa

総合スコア4

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

テスト駆動開発

テスト駆動開発は、 プログラム開発手法の一種で、 プログラムに必要な各機能をテストとして書き、 そのテストが動作する必要最低限な実装を行い コードを洗練させる、といったサイクルを繰り返す手法の事です。

0グッド

0クリップ

投稿2021/04/09 10:02

プログラミング初学者です。
Laravelでtddをやってみようしたらつまずきました。
#環境
ホストOSはWindowsで、Dockerで開発をしています。
Laravel 8.15.0
php 7.3.27

開発用dbとは別にテスト用dbのコンテナを作ってあります。

#質問内容
ユーザーを新規登録する機能をテストを書きながら実装しようとしましたが、テストが通らず、その原因がわからないので教えていただきたいです。

#やったこと
ユーザーの新規登録の際に項目を増やして登録させたかったので、Laravelに最初から存在していたapp/Http/Controllers/Auth/RegisteredUserController.phpの中身を項目だけ増やしてUserController.phpに移しました。

RegisteredUserController

1<?php 2 3namespace App\Http\Controllers\Auth; 4 5use App\Http\Controllers\Controller; 6use App\Models\User; 7use App\Providers\RouteServiceProvider; 8use Illuminate\Auth\Events\Registered; 9use Illuminate\Http\Request; 10use Illuminate\Support\Facades\Auth; 11use Illuminate\Support\Facades\Hash; 12 13class RegisteredUserController extends Controller 14{ 15 /** 16 * Display the registration view. 17 * 18 * @return \Illuminate\View\View 19 */ 20 public function create() 21 { 22 return view('auth.user.register'); 23 } 24 25 /** 26 * Handle an incoming registration request. 27 * 28 * @param \App\Http\Requests\LoginRequest $request 29 * @return \Illuminate\Http\RedirectResponse 30 * 31 * @throws \Illuminate\Validation\ValidationException 32 */ 33 public function store(Request $request) 34 { 35 $request->validate([ 36 'name' => 'required|string|max:255', 37 'email' => 'required|string|email|max:255|unique:users', 38 'password' => 'required|string|confirmed|min:8', 39 ]); 40 41 Auth::login($user = User::create([ 42 'name' => $request->name, 43 'email' => $request->email, 44 'password' => Hash::make($request->password), 45 ])); 46 47 event(new Registered($user)); 48 49 return redirect(RouteServiceProvider::HOME); 50 } 51}

UserController

1<?php 2 3namespace App\Http\Controllers; 4 5use App\Models\User; 6use Illuminate\Support\Facades\Auth; 7use Illuminate\Support\Facades\Hash; 8use Illuminate\Http\Request; 9 10class UserController extends Controller 11{ 12 public function add() 13 { 14 return view('auth.user.create'); 15 } 16 17 /** 18 * @param \App\Http\Requests\LoginRequest $request 19 * @return \Illuminate\Http\RedirectResponse 20 */ 21 public function create(Request $request) 22 { 23 Auth::login($user = User::create([ 24 'user_name' => $request->user_name, 25 'birthday' => $request->birthday, 26 'sex' => $request->sex, 27 'former_job' => $request->former_job, 28 'job' => $request->job, 29 'school_id' => $request->school_id, 30 'email' => $request->email, 31 'password' => Hash::make($request->password), 32 ])); 33 34 return redirect('top'); 35 } 36} 37

そしてUserControllerをテストしたかったので、tests/Feature/RegistrationTest.phpを参考にしてUserControllerTest.phpを作りました。

RegistrationTest

1<?php 2 3namespace Tests\Feature; 4 5use App\Providers\RouteServiceProvider; 6use Illuminate\Foundation\Testing\RefreshDatabase; 7use Tests\TestCase; 8 9class RegistrationTest extends TestCase 10{ 11 use RefreshDatabase; 12 13 public function test_registration_screen_can_be_rendered() 14 { 15 $response = $this->get('/register'); 16 17 $response->assertStatus(200); 18 } 19 20 public function test_new_users_can_register() 21 { 22 $response = $this->post('/register', [ 23 'name' => 'Test User', 24 'email' => 'test@example.com', 25 'password' => 'password', 26 'password_confirmation' => 'password', 27 ]); 28 29 $this->assertAuthenticated(); 30 $response->assertRedirect(RouteServiceProvider::HOME); 31 } 32}

UserControllerTest

1<?php 2 3namespace Tests\Feature; 4 5use App\Models\User; 6use Illuminate\Foundation\Testing\RefreshDatabase; 7use Illuminate\Foundation\Testing\WithFaker; 8use Illuminate\Foundation\Testing\WithoutMiddleware; 9use Tests\TestCase; 10 11class UserControllerTest extends TestCase 12{ 13 use RefreshDatabase; 14 15 /** 16 * ユーザー登録フォームにアクセス出来るかテスト 17 * 18 * @return void 19 */ 20 public function testAdd() 21 { 22 $response = $this->get('/signup'); 23 24 $response->assertStatus(200); 25 } 26 27 /** 28 * ユーザーの新規作成をテスト 29 * @return void 30 */ 31 public function testCreate() 32 { 33 $user = [ 34 'user_name' => '田中 太郎', 35 'birthday' => '2013-5-30 00:00:00.000000', 36 'sex' => 2, 37 'former_job' => '公務員', 38 'job' => 'エンジニア', 39 'school_id' => 1, 40 'email' => 'test@gmail.com', 41 'password' => 'password1', 42 'password_confirmation' => 'password1', 43 ]; 44 45 $response = $this->post('/users/create', $user); 46 47 $this->assertAuthenticated(); 48 $response->assertRedirect('top'); 49 } 50}

ルーティングは以下の通りです。

web

1<?php 2 3use Illuminate\Support\Facades\Route; 4use App\Http\Controllers\UserController; 5use App\Http\Controllers\HomeController; 6 7/* 8|-------------------------------------------------------------------------- 9| Web Routes 10|-------------------------------------------------------------------------- 11| 12| Here is where you can register web routes for your application. These 13| routes are loaded by the RouteServiceProvider within a group which 14| contains the "web" middleware group. Now create something great! 15| 16*/ 17Route::middleware(['guest'])->group(function() { 18 Route::get('/', [HomeController::class, 'index'])->name('top'); 19 Route::get('/signup', [UserController::class, 'add'])->name('add'); 20 Route::post('/users/create', [UserController::class, 'create'])->name('create'); 21}); 22 23require __DIR__.'/auth.php';

テストを実行するとtestCreateが失敗しました。

FAIL Tests\Feature\UserControllerTest ✓ add ⨯ create --- • Tests\Feature\UserControllerTest > create The user is not authenticated Failed asserting that false is true. at tests/feature/UserControllerTest.php:47 43▕ ]; 44▕ 45▕ $response = $this->post('/users/create', $user); 46▕ ➜ 47▕ $this->assertAuthenticated(); 48▕ $response->assertRedirect('top'); 49▕ } 50▕ 51▕ /** Tests: 1 failed, 1 passed Time: 6.54s

testCreate$this->assertAuthenticated();の行をコメントアウトしてテストすると以下のようになります。

FAIL Tests\Feature\UserControllerTest ✓ add ⨯ create --- • Tests\Feature\UserControllerTest > create Response status code [419] is not a redirect status code. Failed asserting that false is true. at tests/feature/UserControllerTest.php:48 44▕ 45▕ $response = $this->post('/users/create', $user); 46▕ 47▕ // $this->assertAuthenticated(); ➜ 48▕ $response->assertRedirect('top'); 49▕ } 50▕ 51▕ /** 52▕ * ユーザー編集フォームにアクセス出来るかテスト Tests: 1 failed, 1 passed Time: 6.56s

ステータスコード419が返ってきているようですが、公式ドキュメントにはテスト実行時に、CSRFミドルウェアはすべてのルートで自動的に無効になります。との記述があるので、原因は別なのではないかと思います。

思いつく限りの手段を試しましたが、3日間いろいろやっても改善しませんでした。
初学者の考えでは限界を感じたのでお力添えいただきたいです。
質問の仕方に不備も多いかと思いますが、よろしくお願い致します。

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

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

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

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

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

guest

回答3

0

おそらくAuth::login()前にエラーが出てるのでdump()でレスポンスを確認。

php

1$response = $this->post('/users/create', $user); 2$response->dump();

htmlから探すのは面倒だけど何らかのエラーメッセージは出てるはずなので探す。

DBではNULL不可だけど$fillableの設定してないとか、外部キーの先がないとかよくある失敗。


他は、ログイン後に表示するならauth。

php

1Route::middleware(['auth'])->group(function() { 2 Route::get('/', [HomeController::class, 'index'])->name('top'); 3}); 4 5Route::middleware(['guest'])->group(function() { 6 Route::get('/signup', [UserController::class, 'add'])->name('add'); 7 Route::post('/users/create', [UserController::class, 'create'])->name('create'); 8});

ログインは成功してるけどguestのせいでtop以外にリダイレクトしてそこでエラー出てる可能性もある。

投稿2021/04/09 12:13

kawax

総合スコア10377

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

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

gasa

2021/04/09 13:00

ご回答ありがとうございます。 $this->withoutMiddleware();をコメントアウトしてから$response->dump();を追記し、実行してみました。以下が結果です。 """ <!DOCTYPE html>\n <html lang="en">\n <head>\n <meta charset="utf-8">\n <meta name="viewport" content="width=device-width, initial-scale=1">\n \n <title>Page Expired</title>\n \n <!-- Fonts -->\n <link rel="dns-prefetch" href="//fonts.gstatic.com">\n <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">\n \n <style>\n /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}a{background-color:transparent}code{font-family:monospace,monospace;font-size:1em}[hidden]{display:none}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{box-sizing:border-box;border:0 solid #e2e8f0}a{color:inherit;text-decoration:inherit}code{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}svg,video{display:block;vertical-align:middle}video{max-width:100%;height:auto}.bg-white{--bg-opacity:1;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity))}.bg-gray-100{--bg-opacity:1;background-color:#f7fafc;background-color:rgba(247,250,252,var(--bg-opacity))}.border-gray-200{--border-opacity:1;border-color:#edf2f7;border-color:rgba(237,242,247,var(--border-opacity))}.border-gray-400{--border-opacity:1;border-color:#cbd5e0;border-color:rgba(203,213,224,var(--border-opacity))}.border-t{border-top-width:1px}.border-r{border-right-width:1px}.flex{display:flex}.grid{display:grid}.hidden{display:none}.items-center{align-items:center}.justify-center{justify-content:center}.font-semibold{font-weight:600}.h-5{height:1.25rem}.h-8{height:2rem}.h-16{height:4rem}.text-sm{font-size:.875rem}.text-lg{font-size:1.125rem}.leading-7{line-height:1.75rem}.mx-auto{margin-left:auto;margin-right:auto}.ml-1{margin-left:.25rem}.mt-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.ml-2{margin-left:.5rem}.mt-4{margin-top:1rem}.ml-4{margin-left:1rem}.mt-8{margin-top:2rem}.ml-12{margin-left:3rem}.-mt-px{margin-top:-1px}.max-w-xl{max-width:36rem}.max-w-6xl{max-width:72rem}.min-h-screen{min-height:100vh}.overflow-hidden{overflow:hidden}.p-6{padding:1.5rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.pt-8{padding-top:2rem}.fixed{position:fixed}.relative{position:relative}.top-0{top:0}.right-0{right:0}.shadow{box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06)}.text-center{text-align:center}.text-gray-200{--text-opacity:1;color:#edf2f7;color:rgba(237,242,247,var(--text-opacity))}.text-gray-300{--text-opacity:1;color:#e2e8f0;color:rgba(226,232,240,var(--text-opacity))}.text-gray-400{--text-opacity:1;color:#cbd5e0;color:rgba(203,213,224,var(--text-opacity))}.text-gray-500{--text-opacity:1;color:#a0aec0;color:rgba(160,174,192,var(--text-opacity))}.text-gray-600{--text-opacity:1;color:#718096;color:rgba(113,128,150,var(--text-opacity))}.text-gray-700{--text-opacity:1;color:#4a5568;color:rgba(74,85,104,var(--text-opacity))}.text-gray-900{--text-opacity:1;color:#1a202c;color:rgba(26,32,44,var(--text-opacity))}.uppercase{text-transform:uppercase}.underline{text-decoration:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.tracking-wider{letter-spacing:.05em}.w-5{width:1.25rem}.w-8{width:2rem}.w-auto{width:auto}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}@-webkit-keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@-webkit-keyframes ping{0%{transform:scale(1);opacity:1}75%,to{transform:scale(2);opacity:0}}@keyframes ping{0%{transform:scale(1);opacity:1}75%,to{transform:scale(2);opacity:0}}@-webkit-keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}@-webkit-keyframes bounce{0%,to{transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:translateY(0);-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}@keyframes bounce{0%,to{transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:translateY(0);-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}@media (min-width:640px){.sm\:rounded-lg{border-radius:.5rem}.sm\:block{display:block}.sm\:items-center{align-items:center}.sm\:justify-start{justify-content:flex-start}.sm\:justify-between{justify-content:space-between}.sm\:h-20{height:5rem}.sm\:ml-0{margin-left:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pt-0{padding-top:0}.sm\:text-left{text-align:left}.sm\:text-right{text-align:right}}@media (min-width:768px){.md\:border-t-0{border-top-width:0}.md\:border-l{border-left-width:1px}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:px-8{padding-left:2rem;padding-right:2rem}}@media (prefers-color-scheme:dark){.dark\:bg-gray-800{--bg-opacity:1;background-color:#2d3748;background-color:rgba(45,55,72,var(--bg-opacity))}.dark\:bg-gray-900{--bg-opacity:1;background-color:#1a202c;background-color:rgba(26,32,44,var(--bg-opacity))}.dark\:border-gray-700{--border-opacity:1;border-color:#4a5568;border-color:rgba(74,85,104,var(--border-opacity))}.dark\:text-white{--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity))}.dark\:text-gray-400{--text-opacity:1;color:#cbd5e0;color:rgba(203,213,224,var(--text-opacity))}}\n </style>\n \n <style>\n body {\n font-family: 'Nunito';\n }\n </style>\n </head>\n <body class="antialiased">\n <div class="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center sm:pt-0">\n <div class="max-w-xl mx-auto sm:px-6 lg:px-8">\n <div class="flex items-center pt-8 sm:justify-start sm:pt-0">\n <div class="px-4 text-lg text-gray-500 border-r border-gray-400 tracking-wider">\n 419 </div>\n \n <div class="ml-4 text-lg text-gray-500 uppercase tracking-wider">\n Page Expired </div>\n </div>\n </div>\n </div>\n </body>\n </html>\n """ テストは失敗しました。 知識がなく、レスポンスの読み方が良くわかりません。申し訳ありません。 Userモデルでは protected $guarded = [ 'id', ]; という指定をしています。 いずれ他のモデルとリレーションを持たせるつもりですが、今のところマイグレーションファイルでは外部キー制約をしていない状態です。 ルーティングはご指摘のようにtopをauthの中にいれてテストしてみましたが、同じように失敗しました。 いろいろとご助言いただきありがとうございます。
guest

0

こちらが参考になるのではないでしょうか
https://teratail.com/questions/264301

投稿2021/04/09 10:17

workshajikoma

総合スコア110

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

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

gasa

2021/04/09 12:12 編集

ご回答ありがとうございます。 今試してみたところ、以下のような結果となりました。 FAIL Tests\Feature\UserControllerTest ⨯ add ✓ create --- • Tests\Feature\UserControllerTest > add Expected status code 200 but received 500. Failed asserting that 200 is identical to 500. at tests/feature/UserControllerTest.php:24 20▕ public function testAdd() 21▕ { 22▕ $response = $this->get('/signup'); 23▕ ➜ 24▕ $response->assertStatus(200); 25▕ } 26▕ 27▕ /** 28▕ * ユーザーの新規作成をテスト Tests: 1 failed, 1 passed Time: 8.20s 調べてみたところ、メソッド内で$this->withoutMiddleware();と追加する方法がありましたので、試してみるとテストが通りました。 RegistrationTestにはwithoutMiddlewareの記述がないことが少し気になりますが、とりあえず解決しました。 お力添えありがとうございました!
guest

0

自己解決

UserControllerTestuse Illuminate\Foundation\Testing\WithoutMiddleware;があることを確認し、testCreateメソッド内に$this->withoutMiddleware();を追加したらテストが通りました!

投稿2021/04/09 12:14

gasa

総合スコア4

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問