概要
テストを書く対象のロジックのなかで外部のAPI(Google OAuthとか)が呼ばれてたりするとテスト書くのが億劫になる今日この頃。
Mockery
を使うと外部APIを呼ばずに戻り値だけ設定でき、さも外部APIが呼ばれたような処理ができ、本当にテストしたい箇所のみテストを書くことができるらしい。
Laravelのドキュメントには実用例書いてなかったのでまとめとくことにしやした。
環境
- php7.2
- laravel5.6
実例
テスト対象のコントローラ
UserController.php
use UserModel;
// 外部APIにリクエスト飛ばしてユーザ情報を取得するメソッドが内包されたクラス
use App\Http\Components\ApiService;
// 外部APIから取得したユーザ情報をDBに登録する処理を書く
public function storeUserAccount()
{
// テストの際はgetUserData()から外部APIにリクエストを飛ばしたくない
$ApiService = new ApiService();
$userData = $ApiService->getUserData();
// 指定したurlへpostした際にちゃんとuserModelにレコードができてるかテストしたい
$attributes = [
'name' => $userData['name'],
'email' => $userData['email'],
'picture_url' => $userData['picture'],
];
$userModel = UserModel::create($attributes);
return view('user.create.complete', [
'user' => $userModel,
]);
}
ルーティング
www.php
Route::post('/user', 'UserController@storeUserAccount')->name('User/Store');
テストコード
指定したURLへリクエストをpostした際にDBへレコードが作成されているかテストする
CreateTest.php
use Mockery;
use Tests\TestCase;
class StoreTest extends TestCase
{
/**
* @dataProvider userData
*/
public function testStoreUser($params)
{
// getUserData()が呼ばれた場合に外部APIへリクエストを飛ばさず
// dataProviderのdummyResponseの値を返す
$ApiServiceMock = Mockery::mock('overload:\App\Http\Components\ApiService');
$ApiServiceMock->shouldReceive('getUserData')
->once()
->andReturn($params['dummyResponse']['userData']);
$url = route('User/Store');
$response = $this->post($url);
$this->assertDatabaseHas('users', [
'name' => $params['dummyResponse']['userData']['name'],
'email' => $params['dummyResponse']['userData']['email'],
'picture_url' => $params['dummyResponse']['userData']['picture'],
]);
}
public function userData()
{
return [
'valid data' => [
[
'dummyResponse' => [
'userData' => [
'name' => 'nus3',
'email' => 'nus3@test.com',
'picture' => 'https://avatars0.githubusercontent.com/u/30946750?s=400&u=79ef67ffa412d27ad46747623a677aa2b83513bd&v=4',
]
]
]
],
];
}
}
余談
テストの正しい書き方を求めて日々奮闘中・・。
何かありましたらコメントや編集リクエストいただけるとありがたいです_:(´ཀ`」 ∠):