
前回の記事でテストを出来る状態にできたので、今回はログイン関係のテストを実装していきます。
バージョン
Laravel 7.x
PHP 7.4.8
どこまで実装するか?
ユーザーのログイン、ログアウトのテストが正しく通る。
新規登録についてはウィザード形式に対応した形でテストを実行できる。
大まかな流れ
ファクトリーの設定
ログインについて
ログアウトについて
新規登録について
という流れでやっていきます。新規登録はウィザード形式で行なっているのをテストしたかったので1番下にしています。
ファクトリーの設定
テストファイルでfactoryを使用出来るように設定を加えていきます。
laravelは最初からuserのfactoryは設定されているので特に記載を加える必要はありません。以下のようにします。
use App\User;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
$factory->define(User::class, function (Faker $faker) {
   return [
       'name' => $faker->name,
       'email' => $faker->unique()->safeEmail,
       'email_verified_at' => now(),
       'password' => bcrypt('Test1234'), // password
       'remember_token' => Str::random(10),
   ];
});
テスト実行コマンドは以下です
./vendor/bin/phpunit --testdox tests/Feature/ファイル名.php
ログインについて
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\User;
class LoginTest extends TestCase
{
   use RefreshDatabase;
   public function setUp(): void
   {
       parent::setUp();                   1
       // テストユーザ作成
       $this->user = factory(User::class)->create();           2
   }
   /**
    * A basic feature test example.
    *
    * @return void
    */
   public function test_正しいパスワードの場合()
   {
       $response = $this->get('/login');          3
       $response->assertStatus(200);
       // ログインする
4      $response = $this->post(route('login'), ['email' => $this->user->email, 'password' => 'Test1234']);
       // リダイレクトでページ遷移してくるのでstatusは302
5      $response->assertStatus(302);
       // リダイレクトで帰ってきた時のパス
6      $response->assertRedirect('/');
       // このユーザーがログイン認証されているか
7      $this->assertAuthenticatedAs($this->user);
   }
}
1, それぞれのテストが実行される前にここに書いた処理が行われるようになります。毎回です。最初だけでは無いことに注意です。
2, 先ほど設定したfactoryを使用してユーザーを作成します。
3, まずはログインページに遷移します。返り値は200が返ってくる事を期待します。
4, postメソッドでルートで飛ばす先、emailとpasswordを書いてログインアクションに飛ばします。
5, ログイン出来たらリダイレクト処理が働くので返り値が302になっているか確認します。
6, リダイレクトで返って来た時のURLの確認をします。
7, ログイン処理したユーザーが認証状態にあるか確認します。
ログインできない場合の処理
emailかpasswordが一致しない場合のテストです。今回はpasswordの方を変更しています
// 省略
public function test_間違ったパスワードの場合()
{
   $response = $this->get('/login');
   $response->assertStatus(200);            1
   // パスワードが正しく無い状態でログイン
2  $response = $this->post('/login', ['email' => $this->user->email, 'password' => 'Test123']);
   // リダイレクトで戻ってくる。
   $response->assertStatus(302);
   // リダイレクトで戻ってきた時はログインページにいる事
3  $response->assertRedirect('/login');
   // 失敗しているので認証されていない事
4  $this->assertGuest();
   
}
1, まずはログインページにアクセスします。
2, パスワードの情報を誤っているものを設定してログイン処理を行います。
3, 正しくログイン出来なかったのでリダイレクト処理でログインページに戻っている事を確認します。
4, ログインに失敗したので認証されていない事を確認します。
今回はパスワードで書いてますが適宜増やしていくところかなと思います。後はエラーメッセージとかも表示されているか確認しても良いかもしれないですね。
ログアウトについて
public function test_ログアウトが正しくできるか()
{
   // ログイン状態の作成
   $response = $this->actingAs($this->user);     1
   $response = $this->get('/');           2
   $response->assertStatus(200);
   // ログアウト処理をする
   $this->post('logout');             3
   // ログアウト出来たら200番が帰ってきているか
   $response->assertStatus(200);       
   // ログインページにいる事
   $response = $this->get('/login');        4
   $response->assertStatus(200);
   // 認証されていないことを確認
   $this->assertGuest();                   5
}
1, ユーザーをログイン状態にします。
2, ホームに戻ります。ログアウトボタンが存在するところならどこでも良いかもです。
3, postアクションでログアウトに処理を飛ばします。
4, ログアウトした後はログインページにいる事を確認します。
5, ログイン状態では無い事を確認します。
新規登録について
普通の登録では無くウィザード形式による登録処理のテストを書いていきます。ページ遷移しながら登録するアレです。
ウィザード形式についても記事がありますので是非!https://note.com/embed/notes/nb4f5bff799cbhttps://note.com/embed/notes/nf49ee45acdaa
ウィザード形式のテストになるとルーティングやコントローラーの設定も絡んできます。その部分については前回書いている記事を対象に書いていますので是非見てみてください。
1つのアクションで全て実行しているので、処理は少し長く感じますが同じことを繰り返している部分が多いのでそこまで複雑ではないです。
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\User;
use Illuminate\Support\Str;
use Session;
use Illuminate\Support\Facades\Hash;
class RegisterTest extends TestCase
{
   use RefreshDatabase;
   /**
    * A basic feature test example.
    *
    * @return void
    */
   public function setUp(): void
   {
       parent::setUp();
       // テストユーザ作成
       $this->user = factory(User::class)->create();
   }
   // 正常系
1  public function test_ログインしていなければ登録ページに遷移できる()
   {
       $response = $this->get('/register');
       $response->assertStatus(200);
   }
2  public function test_正しい値を入力すれば次のページに遷移出来る()
   {
       $response = $this->get('/register');
       $response->assertStatus(200);
3      $password = bcrypt('Test1234');
4      $user_data = [
           'name' => 'test太郎',
           'email' => 'test@test',
           'email_verified_at' => now(),
           'password' => $password,
           // 確認パスワードも必要
           'password_confirmation' => $password,
           'remember_token' => Str::random(10),
       ];
5      $first_path = route('create_address');
6      $response = $this->post($first_path, $user_data);
       // エラーメッセージがないこと
7      $response->assertSessionHasNoErrors(); 
8      $response->assertStatus(200);
       // ページ遷移している事
9      $response->assertViewIs('auth.address');
       // ポップアップ表示が表示されている事
10     $response->assertSeeText('ユーザーは入力完了です!次は住所を入力してください!');
       // セッションの値を取得
11     $all = Session::all();
12     $check_user = [
           'user.name' => 'test太郎',
           'user.email' => 'test@test',
           'user.password' => $all['user']->password
       ];
       // それぞれ入力した値が入っているか確認。下にコメントアウトしている書き方でも同じ意味。
13     $response->assertSessionHasAll($check_user);
       // $response->assertSessionHas('user.name', 'test太郎');
       // $response->assertSessionHas('user.email', 'test@test');
       // $response->assertSessionHas('user.password', $all['user']->password);
       // 住所
       $address_data = [
           'state' => '北海道',
           'town' => 'ニセコ町',
           'street' => '富士見13-1',
           'postal_code' => '0481583',
       ];
       $second_path = route('create_tel');
       $response = $this->post($second_path, $address_data);
       // エラーメッセージがないこと
       $response->assertSessionHasNoErrors(); 
       $response->assertStatus(200);
       // ページ遷移している事
       $response->assertViewIs('auth.tel');
       // ポップアップ表示が表示されている事
       $response->assertSeeText('ユーザー、住所は入力完了です!次は電話番号を入力して登録を完了しましょう!');
       // セッションの値を取得
       $all = Session::all();
       // ユーザー情報は保存されていないので外部キーはまだありません。
14     $check_address = [
           'address.state' => '北海道',
           'address.town' => 'ニセコ町',
           'address.street' => '富士見13-1',
           'address.postal_code' => '0481583',
       ];
       $response->assertSessionHasAll($check_address);
       // 電話番号
       $tel_data = [
           'number' => '566890754336',
       ];
       $third_path = route('create_do');
 15    $response = $this->post($third_path, $tel_data);
       $response->assertSessionHasNoErrors(); 
 16    $response->assertStatus(302);
       // リダイレクトでページ遷移している事
 17    $response->assertRedirect(route('home'));
       // リダイレクトで飛んでいるので、sessionから見つけます。https://qiita.com/NakanishiTetsuhiro/items/96470e796251ba7188f5
 18    $response->assertSessionHas('say','登録が完了しました!');
       // 登録したユーザーのレコードが存在するか
 19    $this->assertDatabaseHas('users', ['name' => 'test太郎']);
       // 登録したユーザーの住所レコードが存在するか
       $this->assertDatabaseHas('addresses', ['state' => '北海道']);
       // 登録したユーザーの電話番号レコードが存在するか
       $this->assertDatabaseHas('tels', ['number' => '566890754336']);
   }
}
1, ログインしてなければ、登録ページに遷移出来る。
2, ここからウィザード形式登録のテストを書いていきます。
3, パスワードはbcryt()メソッドを使って作成します。
4, 登録するユーザー情報を記載します。確認パスワード用も設定する事を忘れずに。
5, routeメソッドを使用してどのアクションに飛ばすのかを定義します。
6, 5で定義したルート情報と登録するユーザー情報を持ってpostアクションでコントローラーに飛ばします。
7, エラーメッセージが無いことを確認します。
8, 正しく処理されているので返り値は200を期待します。
9, 現在いるページはauth.addressである事を確認します。
10, 自分はポップアップ表示を付けているので、表示されているか確認しています。
11, セッションに含まれる値を全て取得します。
12, 含まれているはずの値を定義します。入っている値の形user.nameはコントローラー側でどのように値を代入しているかによります。
13, 12で作ったものがセッションの中に含まれているかを確認します。
住所と電話番号についても同じような流れになっています。パスや値などが若干違うかもしれませんが省略しているところもあります。
14, 12と同じ考え方です。入力された情報として住所に関する欲しいものを記載します。
15, 登録に必要な情報を全て持っている状態でコントローラーの登録処理のアクションに飛ばします。
16, 正しく登録できた時はリダイレクト処理でホームページに飛んできている予定なので、302ステータスになっているか確認します。
17, リダイレクトで戻って来ているのがホームになっているか確認します。
18, リダイレクトで飛んできた際にセッションの中に表示されるはずの文章が含まれているか確認します。
19, ユーザー、住所、電話番号のテーブルにそれぞれ今登録したものが存在しているか確認している。
コントローラー側の記載、ルーティングの記載があった方がわかりやすいかも。
登録処理できない時の処理
今回試しているのは、そもそもログインしているときはアクセス出来ない事、emailの重複、passwordの数制限です。前提としてフォームリクエストのファイルなどが設定されている前提で進めます。
・・省略
 
 // 異常系
   public function test_ログインしていれば登録ページに遷移できない()
   {
 1     $response = $this->actingAs($this->user);
 2     $response = $this->get('/register');
 3     $response->assertStatus(302);
   }
1, ユーザーをログイン状態にします。
2, 登録ページにアクセスしてみます。
3, ログイン状態にあるので、跳ね返されます。ページは存在するけどアクセスする権限が無いので302をステータスで期待します。
public function test_Emailが重複していれば登録できない()
   {
       $response = $this->get('/register');
1      $response->assertStatus(200);     
       $password = bcrypt('Test1234');
       $user_data = [
           'name' => 'test太郎',
2          'email' => $this->user->email,
           'email_verified_at' => now(),
           'password' => $password,
           // 確認パスワードも必要
           'password_confirmation' => $password,
           'remember_token' => Str::random(10),
       ];
3      $first_path = route('create_address');
4      $response = $this->post($first_path, $user_data);
5      $response->assertSessionHasErrorsIn("もうすでに登録されています"); 
6      $response->assertStatus(302);
       // リダイレクトでページ遷移している事
7      $response->assertRedirect(route('register'));
   }
1, 登録ページにアクセスします。
2, emailを既に登録しているユーザーのものと同じものにします。(重複テスト)
3, ルートメソッドを使ってどのアクションに飛ばすかを定義します。
4, 3で設定したパス情報と、登録情報を持ってpostアクションでコントローラー処理に飛ばします。
5, 跳ね返されて、求めているエラーメッセージがsessionに含まれているか確認します。リダイレクトなのでassertSeeが効かなかったりする。
6, 上記で説明した通りリダイレクトなので302である事を確認。
7, リダイレクトで返って来ているところは登録ページである事を確認します。
 public function test_Passwordが8文字以下であれば登録できない()
   {
       $response = $this->get('/register');
 1     $response->assertStatus(200);
 2     $password = 'T';
       $user_data = [
           'name' => 'test太郎',
           'email' => 'test@test',
           'email_verified_at' => now(),
           'password' => $password,
           // 確認パスワードも必要
           'password_confirmation' => $password,
           'remember_token' => Str::random(10),
       ];
       $first_path = route('create_address');
       $response = $this->post($first_path, $user_data);
3      $response->assertSessionHasErrorsIn("パスワードは8文字以上で入力してください");
       $response->assertStatus(302);
       // リダイレクトでページ遷移している事
       $response->assertRedirect(route('register'));
   }
1, 登録ページにアクセスします。
2, パスワードを1文字にします。バリデーションがコントローラーもしくはフォームリクエストに書かれている前提で進めます。
3, リダイレクトで跳ね返って来た時に求めているエラーメッセージがsessionに含まれているか確認します。
まとめ
ファクトリーを使いユーザー情報を作成し、その値を使ってログイン、ログアウトに使用する。
ウィザード形式は1つのアクションの中で全て済むように記載する。assertSessinHas()系のメソッドで入力した情報がセッションに含まれているか、assertViewIs()でページが遷移しているかを確認していく。
ウィザード形式はパターンは基本的に同じ。
ルーティングとコントローラーの情報も関わりが出てくる。
異常系に関しては全然書いてませんが、紹介した異常系の書き方と似ている部分が多いと思います。参考までに。
次やりたい事
SNS認証ログイン関係も今度やってみます。どんな感じなんでしょうw その前にCRUD機能のテストでも良いな〜。
モックとかいうやつとか出て来そうです。触った事ないです。もし出て来たらやってみましょう😄
今回はこんな感じで!
以上!