はじめに
Laravelによる初めてのAPIのテストコードを書いていた
あらかた完成したタイミングで、ふと同僚にコードを見てもらった時に
「Jsonのままテストできるよ」
と指摘され、調べたときのメモ
環境
- PHP 8.0.5
- Laravel 8.5.0
テスト前の準備とテスト内容
Model
まずはApp/Models/User.phpにてユーザーに紐づく注文を取得できるようにリレーションを張る
/**
* ユーザーに紐づく注文の取得.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function orders()
{
return $this->hasMany(Order::class);
}
Controller
Controllerのindexメソッドで返ってくるAPIのJSONデータをテスト
/**
* ユーザーに紐づく注文の取得.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function index()
{
// ログインユーザーの注文の取得
$orders = User::findOrFail(Auth::id())
->orders()
->get();
return response()->json([
'success' => true,
'orders' => $orders->map(function ($orders) {
return [
'uuid' => $orders->uuid,
'name' => $orders->name,
'phone_number' => $orders->phone_number,
'updated_at' => $orders->updated_at->format('Y-m-d H:i:s.u'),
];
}),
]);
}
以下のJsonデータが返ってくるAPIのテストをする
ordersは多重配列構造。
返ってくるJsooデータ
{
success : true,
orders :
[
uuid: ...
name: ...
phone_number: ...
updated_at: ...
],
[
uuid: ...
name: ...
phone_number: ...
updated_at: ...
],
...
}
当初のテストコード
同僚に初めて見せたテストコードがこちら。
/**
* ユーザーに紐づく注文の取得のテスト.
*
* @void
*/
protected function testIndex()
{
// ユーザー、注文情報の取得
$user = User::findOrFail(1); // ここは仮でIDおいてます。
$orders = $user->orders;
// API呼び出し(routeの名前は仮)
$response = $this->actingAs($user)->getJson(route('api.orders.index'));
// jsonデータを配列に変換
$contentArray = json_decode((string) $response->getContent(), true);
$contentArrayCount = count($contentArray['orders']);
// 以下ひたすらテスト
$this->assertCount(2, $contentArrayCount);
$this->assertIsBool($contentArray['success']);
$this->assertIsArray($contentArray['orders'])
$this->assertSame('true', $contentArray['success']);
...
...
}
API呼び出し後に取得値をJsonから配列に置き換えて、PHPUnitにあるメソッドを使ってテストを実行している
どうやってやるの?
では、Jsonのままテストをするにはどうするのさ、と調べるとLaravelドキュメントのHTTPテストを見て即解決した。
assertJsonCountだとかassertJsonといういかにも、なメソッドを発見。
さらにassertJsonとassertableJsonを使うと、今回のような多重配列のJsonでも柔軟なテストが可能であった。
assertJsonについて実用的な書き方は以下記事で書いていますので、初めてAPIテストコードを書く方のお役に立てると嬉しいです。
修正後のテストコード
/**
* ユーザーに紐づく注文の取得のテスト.
*
* @void
*/
protected function testIndex()
{
// ユーザー、注文情報の取得
$user = User::findOrFail(1); // ここは仮でIDおいてます。
$orders = $user->orders;
// API呼び出し(routeの名前は仮)
$response = $this->actingAs($user)->getJson(route('api.orders.index'));
// 以下ひたすらテスト
$this->assertJsonCount(2);
$response->assertJson(function (AssertableJson $json) use ($contentArrayCount) {
$json->whereAllType([
'success' => 'boolean',
'orders' => 'array',
]);
$json->where('success', true);
}, true);
...
...
}
Jsonのままテストができるので、配列に置き換える必要がなくなった。
おわりに
初めての作業であれば、ちゃんと公式ドキュメントは読もう。
得るものは大きかった。