この記事のゴール
- 前回書いた記事で使ったテストコードの理解
※前回書いた記事はこちら
前回書いたテストコード
簡単なテストケースを書いただけのつもりでしたが、だいぶ長くなったので
細切れで説明していきます。
テストクラスの命名ルール
class 宣言でクラス名の命名ルールですが、基本的には機能単位のテストになるので、
テスト対象の機能名に「Test」を接尾辞として付けたものを名称にします。
ここではテスト対象の機能が「TODO」機能なので「Todo」を機能名とし、
その後ろに「Test」を付けて「TodoTest」としています。
このクラス名とファイル名は必ず合わせましょう。
違っているとテスト時に叱られます。
「TodoTest」クラスなので、ファイル名は「TodoTest.php」です。
ファイル名は、作成時にartisanコマンドを使っていれば気にならないかもしれません。
テストメソッドの命名ルール
厳密な規則としては最初の「testで始める」ことと、PHPの関数名のルールに従うことだけです。
開発現場によって命名規則が変わると思います。
一応、筆者が採用しているルールは次の通りです。
- test で始める
- 単語間の空白はアンダースコア「_」で埋める
- 次にメソッド名を入れる
- 次にテスト内容がわかる説明的な名前を入れる
テスト実行時にエラーが出た場合、このメソッド名が説明的だと対応しやすくなります。
説明:冒頭部分
まずは最初の部分を見ていきましょう。
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\Models\Todo;
class TodoTest extends TestCase
{
3行目で名前空間の定義があります。Laravelは機能テストを重視しているので、
Tests\Feature となっています。
5行目~7行目の use宣言3行分はデフォルトです。
8行目の use宣言は、Todo モデルを使うということです。
10行目の class 宣言でクラス名の命名ルールに則り「TodoTest」クラスにしています。
extends TestCase でLaravelの機能を使えるようにしたTestCaseクラスを継承します。
説明:TODOリスト表示のテストメソッド
これは TodoControllerのindex()メソッドのテストをするメソッドと言えると思います。
TODOリスト一覧表示ページを表示させる箇所です。
public function test_index_can_get_todo_list(): void
{
Todo::truncate();
$todos = Todo::factory()->count(5)->create();
$response = $this->get(route('todo.index'))
->assertSee('TODOリスト')
->assertSee('新規登録')
->assertOk();
foreach ($todos as $todo) {
$response->assertSee($todo->todo);
}
}
メソッド名は「test_index_can_get_todo_list」、
「indexがTODOリストを取得できる」ことを確認するテストです。
Todo::truncate();
truncate()で一旦、todosテーブルの中身を空にしています。(厳密にはテーブル作りなおし)
$todos = Todo::factory()->count(5)->create();
ファクトリーを使って5行分、ダミーデータのレコード挿入をしています。
その結果作成された5行分のレコードの内容を、EloquentのCollectionオブジェクトとして
$todos に格納しています。後で検証に使います。
$response = $this->get(route('todo.index'))
->assertSee('TODOリスト')
->assertSee('新規登録')
->assertOk();
route(‘todo.index’) でTODOリストページのURLを取得しています。
http://localhost/todo/ ですね。
$this->get() の引数にURLを渡すとそこにアクセスした結果をオブジェクトで返すので、
メソッドチェーンで次々に検証を続けることができます。
assertSee(‘TODOリスト’) で、HTTPレスポンのHTML内に「TODOリスト」があるか
検証しています。あればOK、なければエラーになります。
assertOk() はHTTPレスポンスコードが200であることを検証しています。
assertStatus(200) と同じです。
Laravel で利用できるこれらのアサーションは公式サイトで確認しましょう。
![](https://laravel.com/img/og-image.jpg)
foreach ($todos as $todo) {
$response->assertSee($todo->todo);
}
最初に作成した5行分のレコードについて、
todo項目の内容が表示されていることを検証しています。
説明:TODO詳細表示のテストメソッド
public function test_retrieve_can_be_rendered(): void
{
Todo::truncate();
$todos = Todo::factory()->count(5)->create();
foreach ($todos as $todo) {
$this->get(route('todo.detail', ['id' => $todo->id]))
->assertSee('TODO詳細')
->assertSee('[編集]')
->assertSee('[削除]')
->assertSee('todo一覧')
->assertSee('やること: ' . $todo->todo)
->assertSee('状態:' . (1 == $todo->done ? '完了' : ''))
->assertOk();
}
}
ここも最初に truncate() でテーブルを空にしています。
それからダミーデータを5行分挿入し、対象レコードのデータを$todosに格納しています。
5行分のレコード全てについて、詳細ページにアクセスし、
該当データが表示されていることを検証しています。
$this->get(route('todo.detail', ['id' => $todo->id]))
詳細ページのURLにはID指定が必用なので、$todo->id で渡しています。
説明:TODO新規登録フォーム表示のテスト
public function test_create_can_be_rendered(): void
{
$this->get(route('todo.create'))
->assertSee('TODO新規登録')
->assertSee('やること:')
->assertSee('登録')
->assertSee('取消')
->assertOk();
}
特に説明は要らないと思います。表示の確認とHTTPステータスコードの確認です。
説明:TODO新規登録のテスト
public function test_store_can_store(): void
{
$todo = Todo::factory()->definition();
$this->post(route('todo.store'), $todo)
->assertValid()
->assertRedirect(route('todo.index'));
$this->get(route('todo.index'))
->assertSee($todo['todo']);
}
これはページはありませんが、重要な機能として存在するのでテストします。
$todo = Todo::factory()->definition();
覚えていますか?ファクトリー作成時にダミーデータを配列で返すメソッドを
作ったと思いますが、そのメソッド名が definition() です。
※覚えていない場合はこちらで確認
そのメソッド呼び出しで、登録するためのデータを配列として受け取っています。
$this->post(route('todo.store'), $todo)
->assertValid()
->assertRedirect(route('todo.index'));
post() メソッドは第一引数がURL、第二引数がPOSTするデータのハッシュ配列です。
コントローラー側でPOSTデータのバリデーションが行われるので、
assertValid() でバリデーションエラーが無いことを検証しています。
assertRedirect() で、引数のURLにリダイレクトのレスポンスが返ったことを検証しています。
注意が必要なのは、ここで受け取っているHTTPレスポンスが、
リダイレクト先のものではなく、アクセスしたURLが返したリダイレクト指定の内容
であることです。HTTPレスポンスコードが301または302で、
レスポンスヘッダとHTML内にリダイレクト先のURLが表示されています。
$this->get(route('todo.index'))
->assertSee($todo['todo']);
というわけで、リダイレクト先のURLには改めてアクセスする必要があります。
説明:TODO編集フォーム表示のテスト
public function test_edit_can_be_rendered(): void
{
Todo::truncate();
$todos = Todo::factory()->count(5)->create();
foreach ($todos as $todo) {
$this->get(route('todo.edit', ['id' => $todo->id]))
->assertSee('TODO編集')
->assertSee('取消')
->assertSee('やること:')
->assertSee($todo->todo)
->assertSee('状態:')
->assertSee('未完')
->assertSee('完了')
->assertSee('登録')
->assertOk();
}
}
もう見ただけでわかると思います。
テーブルを空にしてからダミーデータ5行挿入、
5行分それぞれの編集フォームにアクセスして
該当データが表示されているかを確認しています。
説明:TODOデータ更新のテスト
public function test_update_can_update(): void
{
Todo::truncate();
$todos = Todo::factory()->count(5)->create(['done' => 0]);
$id = 2;
$todo = 'update:' . $todos[$id]->todo;
$this->patch(route('todo.update', ['id' => $id]), [
'todo' => $todo,
'done' => 1,
])
->assertValid()
->assertRedirect(route('todo.detail', ['id' => $id]));
$this->get(route('todo.index'))
->assertSee($todo);
}
いつも通りテーブルを空にしてからダミーデータを5行挿入しています。
$todos = Todo::factory()->count(5)->create(['done' => 0]);
create() の引数にハッシュ配列で項目の値を指定してレコード作成ができます。
ここでは、done = 0 つまり「未完」の状態のレコードを5行挿入しています。
$todo = 'update:' . $todos[$id]->todo;
更新した内容であることが判別できるように、最初に「update:」を付加しています。
$this->patch(route('todo.update', ['id' => $id]), [
'todo' => $todo,
'done' => 1,
])
->assertValid()
->assertRedirect(route('todo.detail', ['id' => $id]));
更新する際のHTTPメソッドはPATCHです。
更新する内容をハッシュで渡しています。先程の「update:」を付加したtodoと、
done=1 「完了」として渡しています。
assertValied() でバリデーションエラーが無いことの検証をしています。
assertRedirect() で詳細ページへのリダイレクトを検証しています。
$this->get(route('todo.index'))
->assertSee($todo);
TODO一覧ページにアクセスして、更新したtodoが表示されいていることを検証しています。
説明:TODO削除のテスト
public function test_destroy_can_destroy(): void
{
Todo::truncate();
$todos = Todo::factory()->count(5)->create();
$id = 2;
$this->delete(route('todo.destroy', ['id' => $id]))
->assertRedirect(route('todo.index'));
$todos = Todo::all();
foreach ($todos as $todo) {
$this->assertTrue($todo->id !== $id);
}
}
テーブルを空にしてからダミーデータを5行挿入しています。
id=2 のレコードを削除していきます。
$this->delete(route('todo.destroy', ['id' => $id]))
->assertRedirect(route('todo.index'));
内容の削除時のHTTPメソッドは DELETE です。
TODO一覧ページへのリダイレクトを検証しています。
$todos = Todo::all();
foreach ($todos as $todo) {
$this->assertTrue($todo->id !== $id);
}
レコード全件取得して $todos に格納してから、
レコード毎に、id が 削除したレコードのものではないことを検証しています。
以上です。お疲れまでした。
コメント