はい、今回はSanctumを使ったログインAPIのテストコードを書いてみました!
Tokenを使っているのでその辺も考えながらテストを書いていきます~
Table of Contents
テストコード
ではテストケースを作成しましょう。
php artisan make:test AuthenticationTest
Code language: CSS (css)
いったんテストコードを共有!
説明は後から~
tests/Feature/AuthenticationTest.php
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use Illuminate\Testing\Fluent\AssertableJson; //追加
class AuthenticationTest extends TestCase
{
use DatabaseTransactions;
public function test_example()
{
$response = $this->get('/');
$response->assertStatus(200);
}
/**
* テスト前に共通処理を実行する。
*/
public function setUp():void
{
//親クラスのセットアップメソッドを実行する。
parent::setUp();
//テスト用のダミーユーザの作成
$this->user = User::create([
"name" => "auth_test_user",
"password" => bcrypt('auth_test_password'),
]);
}
/**
* ログイン認証テスト
*/
public function testLogin()
{
//現在作成されているユーザで認証のリクエスト
$response = $this->json('POST', route('route.login'),[
'name' => 'auth_test_user',
'password' => 'auth_test_password',
]);
//正しいレスポンスが返ってきているのか
$response->assertStatus(200);
//data typeチェック
$response->assertJson(fn (AssertableJson $json) =>
$json->whereType('success', 'boolean')
->whereType('summary', 'string')
->whereType('details', 'array')
->whereAllType([
'details.token' => 'string',
])
);
//テスト用のユーザがログインしているのか確認
$this->assertAuthenticatedAs($this->user);
}
/**
* ログアウトテスト
*/
public function testLogout()
{
//再度ログインしてtokenを取得する。
$response = $this->json('POST', route('route.login'),[
'name' => 'auth_checker',
'password' => 'auth_test_code',
]);
$token = $response->json('details.token');
// actingAsヘルパで現在認証済みのユーザーを指定
$response = $this->actingAs($this->user);
//ログアウト処理
$response = $this->json('POST', route('route.logout'),[
'Beare Token' => $token,
]);
//正しいレスポンスが返ってきているかどうかを確認。
$response->assertStatus(200);
}
}
Code language: HTML, XML (xml)
DatabaseTransactions
DatabaseTransactionsを利用することによって、テストを実行している間だけ、有効なトランザクションを作ってくれるんです。
まあ、何が言いたいかというと、テストコード用にユーザを作ったりすることができるということです。
そしてテストが終わると元の形にロールバックしてくれルわけです。あら便利。
//classの上の方でたくさん定義しているところに追記する。
use Illuminate\Foundation\Testing\DatabaseTransactions;
//classの中に追加する。
use DatabaseTransactions;
Code language: PHP (php)
setUpメソッド
今回はsetUpメソッドを使ってテスト用のダミーユーザを作成してみました。
setUp複数のメソッド内で利用するような値を事前に定義することができます。
参考→【Laravel】テストで使用するsetUpメソッドについて
今回の場合は、テスト用のユーザを作成しています。
public function setUp():void
{
//親クラスのセットアップメソッドを実行する。
parent::setUp();
}
Code language: PHP (php)
上記を追加しないとsetUpメソッドではエラーがでるっぽいですね。
voidとparent::setUp()が必要なようです。
ログインのテストコード
はい、まずはログインのメソッドの説明です。
テストコードでは基本的に予測していた値が返ってくるのかをチェックするので、Laravel公式 HTTPテストを確認しながら進めてみましょう。
/**
* ログイン認証テスト
*/
public function testLogin()
{
//現在作成されているユーザで認証のリクエスト
$response = $this->json('POST', route('route.login'),[
'name' => 'auth_test_user',
'password' => 'auth_test_password',
]);
//正しいレスポンスが返ってきているのか
$response->assertStatus(200);
//data typeチェック
$response->assertJson(fn (AssertableJson $json) =>
$json->whereType('success', 'boolean')
->whereType('summary', 'string')
->whereType('details', 'array')
->whereAllType([
'details.token' => 'string',
])
);
//テスト用のユーザがログインしているのか確認
$this->assertAuthenticatedAs($this->user);
}
Code language: PHP (php)
今回行ったのは以下
- ログインしたときに正しいレスポンスが返ってきたかどうか assertStatus()
- レスポンスデータのdata-typeは正しいのかどうか assertJson
- ログインしたユーザは本当にログインできているのかどうか? assertAuthenticatedAs
これらassertXXXXX()メソッドの使い方はLaravel8公式の「利用可能なアサート」という項目からチェックしてみてくださいね。
あああああ、assertJson()のかっこの中にあるfnはアロー関数を意味しているようだ。この使い方しらなかったー(;’∀’)
ちなみに今回はレスポンスデータのデータタイプしかチェックしていないけど、以下みたいにするとレスポンスデータの文字もチェックできますよ。
// 値のチェック
$message = "create";
$response
->assertJsonPath('success', true)
->assertJsonPath('message', "$message success!")
;
Code language: PHP (php)
ログインはこれでOK
ログアウトのテストコード
ログアウトのテストコードは以下です。
/**
* ログアウトテスト
*/
public function testLogout()
{
//再度ログインしてtokenを取得する。
$response = $this->json('POST', route('route.login'),[
"name" => "auth_test_user",
"password" => bcrypt('auth_test_password'),
]);
$token = $response->json('details.token');
// actingAsヘルパで現在認証済みのユーザーを指定
$response = $this->actingAs($this->user);
//ログアウト処理
$response = $this->json('POST', route('route.logout'),[
'Beare Token' => $token,
]);
//正しいレスポンスが返ってきているかどうかを確認。
$response->assertStatus(200);
}
Code language: PHP (php)
これなんでLoginメソッドを呼び出さないで、ログインをやり直しているのかというと、あえてやっています。
一応テストコードとしての可読性を上げるためにやっています。
賛否あるっぽいですが、一応こんな記事も→テストコードの期待値はDRYを捨ててベタ書きする ~テストコードの重要な役割とは?~
結局は読みやすかったらいいんだろなーっておもてます。
テストを走らせてみる
ほい、最後にテストを走らして何もなかったらOKです!
//全体をテストする
php artisan test
//特定のテストケースのみのテストを行う。
php artisan test ./tests/Feature/AuthenticationTest.php
Code language: JavaScript (javascript)
実際にこんな感じになればOK!
$ php artisan test
PASS Tests\Feature\AuthenticationTest
✓ login
✓ logout
Tests: 2 passed
Time: 0.28s
完璧だ!OK
まとめ
テストを書くことで運用や、そのあとのバグとかも減って後々楽にもなるからできるだけ書いていきたいですね~