Laravelでテストデータを入れるfactoryは使ったことがありましたが、コードが正確に動いているかのテストもできるんですね!すごい。
ということで、ユーザー登録の流れをテストすべく、UnitTestを使ってみました。
UnitかFeatureか
testsディレクトリはLaravelが予め用意してくれており、その中にさらにUnit と Feature ディレクトリに分かれています。
どっちを使えばいいのか?ということですが、基本「絶対にどっちじゃないとダメ!」ということはないようです。
ただ、
Unit : 最小単位・最小機能でのテスト
Feature : 機能が組み合わせられているような場合のテスト
「大体こう↑↑分けるといいですよ〜」と用意してくれているようなので、なるべくそれに倣おうと思います。
追記:今もまだ使い分けはあやふやですが以下のような違いがあるそうです。
Unit・・・クラスファイル単位でのテスト。モデルやコントローラーなど
feature・・・ルーティング〜Controller、モデル、DBなど含めてテスト
/tests/Feature/ExampleTest.php を編集
全体のコードはこんな感じ。今回は既存のExampleTest.phpを使用しました。
テストの実行は、ターミナルに vendor/bin/phpunit を入力します。
use Illuminate\Foundation\Testing\DatabaseTransactions; class ExampleTest extends TestCase { use DatabaseTransactions; /** * A basic test example. * * */ public function testBasicTest() //① { $response = $this->get('/')->assertStatus(200); $response = $this->get('/register')->assertOk(); $response = $this->get('/hoge')->assertStatus(404); $response = $this->get('/register')->assertSeeText('Name'); $response = $this->get('/register')->assertSee('form'); } /** * A basic test example. * regietsrから確認画面へ * */ public function testPostTest() //② { $response = $this->post('/confirm' ,[ 'name' => 'test', 'email' => 'test555@gmail.com', 'password' => '11111111', 'password_confirmation' => '11111111', ]); $response->assertStatus(200); } /** * A basic test example. * 確認画面からさらに登録へPOST * @depends testBasicTest */ public function testPost2Test() //③ { $response = $this ->post('/registered' ,[ 'name' => 'test', 'email' => 'test555@gmail.com', 'password' => '11111111', 'password_confirmation' => '11111111', ]); $response->assertRedirect('/home'); }
記述内容
①ベーシックなページ表示テスト
1つ目のテストは練習がてら、単純にページが表示されるかのチェックです。
public function testBasicTest() { $response = $this->get('/')->assertStatus(200); // '/'のレスポンスは200か $response = $this->get('/register')->assertOk(); // 上と同じ。レスポンス200か $response = $this->get('/hoge')->assertStatus(404); // '/hoge'にアクセスすると404か $response = $this->get('/register')->assertSeeText('Name'); // '/register'内にテキストで'Name'という値はあるか $response = $this->get('/register')->assertSee('form'); // '/register'内にhtmlタグで form はあるか }
いずれもアクセスできるかorできないか、や表示内容を確認しているものになります。
assertSee('form')はassertSee('<form')と書くとなぜかエラーになってしまいました。
②Post送信テスト
次は、 登録フォームからPOST送信した場合のテストです。
POST送信する先は、 /confirm になっています。
public function testPostTest() { $response = $this->post('/confirm' ,[ 'name' => 'test', 'email' => 'test555@gmail.com', 'password' => '11111111', 'password_confirmation' => '11111111', ]); $response->assertStatus(200); }
$response = $this->post
の引数に、飛び先のurlとPOST送信される各データがセットされています。
③確認画面から登録処理へ
先ほどの入力画面から /confrimの確認画面まで来たので、内容を確認後、最後のPOST送信をした場合のテストです。
/** * A basic test example. * 確認画面からさらに登録へPOST * @depends testBasicTest */ public function testPost2Test() //③ { $response = $this ->post('/registered' ,[ 'name' => 'test', 'email' => 'test555@gmail.com', 'password' => '11111111', 'password_confirmation' => '11111111', ]); $response->assertRedirect('/home'); }
内容はほとんど同じですが、登録後にちゃんと /home にリダイレクトされるかを確認しています。
詰まった点
ステータスが419になっているというエラー
これは@csrfが無いことによるエラーで、検索したところ「use WithoutMiddleware」のようにトレイトをuseすればいいという解決策があったのですが、こちらを使ったところそれまで正常だった箇所までおかしくなったので慌てて削除。
おかしいなーと思って他のも触っているうちに直りました。。ので、問題は@csrfじゃなかったのかも。。。
Failed asserting that two strings are equal.
$response->assertRedirect('/');
と記述した場所に対してこのようなエラーが出ました。
http://localhost にリダイレクトされるのを期待していたけど
実際には http://localhost/home にリダイレクトされたよ
というエラーです。
これは私の記述ミスですね。。。/homeにリダイレクトされるのが正しい挙動なので、
$response->assertRedirect('/home');
に書き直したら解決。
テストするとテーブルに挿入される
私の勝手な思い込みで、テストだから実際DBにはインサートされないんだろう!と何度もテストを実行して、何かしらのエラーが発生していました・・・。
実際にはDBに書き込みがされるようです。
マニュアルの「トランザクションの使用」に書いてあるように、
use Illuminate\Foundation\Testing\DatabaseTransactions; //←ここ class ExampleTest extends TestCase { use DatabaseTransactions; //←ここ
の二箇所を記述して、post用の入力値を新しく書き換えればOKです!
まとめ
あれば便利なテスト環境。でもテスト環境でもエラーが出るのか〜
ちゃちゃっと書けるようになりたい!