サイトアイコン 上尾市のWEBプログラマーによるブログ

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

フィーチャーテスト

テストクラスの作成

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');
  }
}

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

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');
  }
}

フィクスチャ

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

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

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');
  }
  // 以下省略

バリデーションのテスト

/** @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');
}

アクセス制御のテスト

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);
}

テーブル更新のテスト

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

モバイルバージョンを終了