「基礎から学ぶLaravel」の感想・備忘録4

スポンサーリンク

フィーチャーテスト

テストクラスの作成

  • sail artisan make:test MessageTest
    tests/Feature/MessageTest.phpが生成される。
  • sail test tests/Feature/MessageTest.phpで実行(sail testで全てのテストを実行)
  • テストメソッド名はtest_で始める、または/** @test */を付ける。
  • テストメソッド名はテスト結果に表示され、外部から呼び出されることはないので、日本語にすることもある。
  • データベースはテスト実行時にマイグレーションが実行されるようになっている。
    データはテストメソッド内で生成する必要がある。
  • use RefreshDatabase;とするとテストを実行するたびにデータベースがリフレッシュされる。
    ただし、オートインクリメントの値はリセットされないので注意!
  • assertSee()でテキストをチェックすることができる。
  • assertSeeInOrder()で表示順もチェックすることができる。
class MessageTest extends TestCase
{
  use RefreshDatabase;
  
  /** @test */
  public function メッセージ一覧の表示(): void
  {
    $message = new Message();
    $message->body = 'Hello World';
    $message->save();
    $this->get('messages')->assertStatus(200)->assertSee('Hello World');
  }
}

認証のフィーチャーテスト

  • sail artisan make:test AuthenticationTest
  • assertRedirect()でレスポンスがリダイレクトであることを確認することができる。
  • assertAuthenticatedAs()で認証されていることを確認することができる。(第2引数はガード名)
  • assertGuest()で認証されていないことを確認することができる。(引数はガード名)
  • from()で送信元URLを指定することができる。
    認証失敗時は送信元にリダイレクトされる。(FormRequestでバリデーションエラーとなるため)
    送信元を指定しないと、送信元はルート(‘/’)となる。
  • assertInvalid()でエラーメッセージを確認することができる。
class AuthenticationTest extends TestCase
{
  use RefreshDatabase;

  /** @test */
  public function ログイン画面の表示(): void
  {
    $response = $this->get(route('admin.login'))->assertStatus(200);
  }

  /** @test */
  public function ログイン成功(): void
  {
    $admin = new Admin();
    $admin->name = '管理者';
    $admin->login_id = 'admin';
    $admin->password = Hash::make('hoge');
    $admin->save();
    $this->post('/admin/login', [
      'login_id' => 'admin',
      'password' => 'hoge',
    ])->assertRedirect(route('book.index'));
    $this->assertAuthenticatedAs($admin, 'admin');
  }

  /** @test */
  public function ログイン失敗(): void
  {
    $admin = new Admin();
    $admin->name = '管理者';
    $admin->login_id = 'admin';
    $admin->password = Hash::make('hoge');
    $admin->save();
    $this->from(route('admin.login'))->post('/admin/login', [
      'login_id' => 'admin',
      'password' => 'hogehoge',
    ])->assertRedirect(route('admin.login'))
      ->assertInvalid(['login_id' => 'credentials do not match']);
    $this->assertGuest('admin');
  }
}

フィクスチャ

上記の認証テストではテスト毎にユーザーを作成しているが、フィクスチャを使うと事前処理や事後処理を設定することができる。

フィクスチャには以下の種類がある。

  • setUp: テストメソッドが呼ばれる前
  • tearDown: テストメソッドが呼ばれた後
  • setUpBeforeClass: クラス内のテストメソッドが呼ばれる前
  • tearDownAfterClass: クラス内のテストメソッドが全て呼ばれた後
class AuthenticationTest extends TestCase
{
  use RefreshDatabase;

  private $admin;

  public function setUp(): void
  {
    parent::setUp();
    $this->admin = new Admin();
    $this->admin->name = '管理者';
    $this->admin->login_id = 'admin';
    $this->admin->password = Hash::make('hoge');
    $this->admin->save();
  }

  /** @test */
  public function ログイン画面の表示(): void
  {
    $response = $this->get(route('admin.login'))->assertStatus(200);
  }

  /** @test */
  public function ログイン成功(): void
  {
    $this->post('/admin/login', [
      'login_id' => 'admin',
      'password' => 'hoge',
    ])->assertRedirect(route('book.index'));
    $this->assertAuthenticatedAs($this->admin, 'admin');
  }
  // 以下省略

バリデーションのテスト

  • assertInvalid()で指定したキーにエラーがないことを確認することができる
/** @test */
public function バリデーション(): void
{
  $routeLoginForm = route('admin.login');
  $routeLogin = '/admin/login';

  // ID未入力
  $this->from($routeLoginForm)->post($routeLogin, [
    'login_id' => '',
  ])->assertRedirect($routeLoginForm)
    ->assertInvalid(['login_id' => 'login id field is required']);
  $this->assertGuest('admin');

  // ID入力
  $this->from($routeLoginForm)->post($routeLogin, [
    'login_id' => 'aaa',
  ])->assertRedirect($routeLoginForm)
    ->assertValid('login_id');
  $this->assertGuest('admin');

  // パスワード未入力
  $this->from($routeLoginForm)->post($routeLogin, [
    'password' => '',
  ])->assertRedirect($routeLoginForm)
    ->assertInvalid(['password' => 'password field is required']);
  $this->assertGuest('admin');

  // パスワード入力
  $this->from($routeLoginForm)->post($routeLogin, [
    'password' => 'aaa',
  ])->assertRedirect($routeLoginForm)
    ->assertValid('password');
  $this->assertGuest('admin');
}

アクセス制御のテスト

  • sail artisan make:test BookUpdateTest
  • actingAs()で認証済みにすることができる。(第1引数はモデルインスタンス、第2引数はガード名)
  • assertForbidden()で403を確認することができる。
  • 更新処理のアクセス制御はここでは省略するが、本文には以下の内容が書かれている 。
    • $this->put($route, $param)のように第2引数に連想配列でフォームデータを渡すことができる。
    • assertSameメソッドは第1引数と第2引数が一致することを確認することができる。
    • モデルのfreshメソッドはDBの最新の値を再取得する
private $admin;
private $book;

public function setUp(): void
{
  parent::setUp();
  // Admin, Bookの登録処理はここでは省略
}
public function 更新画面のアクセス制御(): void
{
  $route = route('book.edit', $this->book);

  // 未認証の場合
  $this->get($route)->assertRedirect(route('admin.login'));

  // Admin.idとBook.admin_idが一致しない場合
  $admin2 = new Admin();
  $admin2->name = '管理者2';
  $admin2->login_id = 'admin2';
  $admin2->password = Hash::make('hoge');
  $admin2->save();
  $this->actingAs($admin2, 'admin');
  $this->get($route)->assertForbidden();

  // Admin.idとBook.admin_idが一致する場合
  $this->actingAs($this->admin, 'admin');
  $this->get($route)->assertStatus(200);
}

テーブル更新のテスト

ここでは省略するが、本文には以下の内容が書かれている。

  • assertDatabaseHas('books', $param)にようにするとDBの値が更新されたかどうかを確認することができる。
    第1引数:テーブル名, 第2引数: 連想配列
  • 反対にデータが存在しないことを確認するassertDatabaseMissingメソッドもある。

コメント