概要
Real Time Facade が便利だったけどあまりそれについての tips とかがなかったので書いてみる.
テストしにくいような処理を Real Time Facade を用いてサクッとテストかけるよっていう紹介.
準備
Qiita の投稿一覧を API で取得して、そのタイトルを一覧するような処理を書く.
多分 QiitaController みたいな感じでこうなる
# Controller 作成
php artisan make:controller QiitaController
コントローラーの中身はこんな感じ
<?php // app/Http/Controllers/QiitaController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class QiitaController extends Controller
{
public function index(Request $request)
{
$page = $request->input('page', 1);
$perPage = $request->input('per_page', 20);
$jsonResponse = file_get_contents("https://qiita.com/api/v2/items?page={$page}&per_page={$perPage}");
$response = json_decode($jsonResponse, true);
$str = '<ul>';
foreach ($response as $item) {
$str .= '<li>' . $item['title'] . '</li>';
}
$str .= '</ul>';
return $str;
}
}
テスト書いてみる
php artisan make:test QiitaControllerTest
多分中身はこんな感じ
<?php
namespace Tests\Feature;
use Tests\TestCase;
class QiitaControllerTest extends TestCase
{
public function testIndex()
{
$response = $this->get('/qiita');
$response->assertStatus(200);
}
}
とりあえずこれでテストは通る。
これでもいいけど、これはQiitaのサイトのステータスやネットワークの状態によってテストの結果が変わってしまう。
もう少しかっこよくしたい。
処理のまとまりを切り出す
方針としては、API取得の部分を関数に切り出すと良さそう。
仮に QiitaApi というクラスに切り出してみよう。
<?php // QiitaApi
namespace App;
class QiitaApi
{
public function getItems($page = 1, $perPage = 20)
{
$jsonResponse = file_get_contents("https://qiita.com/api/v2/items?page={$page}&per_page={$perPage}");
$response = json_decode($jsonResponse, true);
return $response;
}
}
こんな感じ
このクラスを利用したコントローラーは下記のように修正する
<?php
namespace App\Http\Controllers;
use App\QiitaApi;
use Illuminate\Http\Request;
class QiitaController extends Controller
{
public function index(Request $request)
{
$api = new QiitaApi();
$page = $request->input('page', 1);
$perPage = $request->input('per_page', 20);
$response = $api->getItems($page, $perPage);
$str = '<ul>';
foreach ($response as $item) {
$str .= '<li>' . $item['title'] . '</li>';
}
$str .= '</ul>';
return $str;
}
}
Facade を導入する
少し良くなったけど、まだテストし辛いのは変わらない。
ここで本題の Read Time Facade を導入して書いてみる。
5.4から導入された Real Time Facade は、use する namespace のアタマに Facades とつければそのクラスを Facade として利用できるというものらしい。
この黒魔術は localdisk さんが記事を書いているのでそちらを参照されたいhttp://tech.innovator.jp.net/entry/2017/08/29/135714
<?php
namespace App\Http\Controllers;
use Facades\App\QiitaApi;
use Illuminate\Http\Request;
class QiitaController extends Controller
{
public function index(Request $request)
{
$page = $request->input('page', 1);
$perPage = $request->input('per_page', 20);
$response = QiitaApi::getItems($page, $perPage);
$str = '<ul>';
foreach ($response as $item) {
$str .= '<li>' . $item['title'] . '</li>';
}
$str .= '</ul>';
return $str;
}
}
テストでモックを使う
さて、ここまでできたらAPI取得をQiitaのステータスやネットワークの状態に依存しないように QiitaApi クラスをモックしてみよう。
テストは下記のように書くことができる。
<?php
namespace Tests\Feature;
use Facades\App\QiitaApi;
use Tests\TestCase;
class QiitaControllerTest extends TestCase
{
public function testIndex()
{
QiitaApi::shouldReceive('getItems')
->withAnyArgs()
->once()
->andReturn([
['title' => 'hoge'],
['title' => 'fuga'],
['title' => 'piyo'],
]);
$response = $this->get('/qiita');
$response->assertStatus(200);
$response->assertSeeText('hoge');
$response->assertSeeText('fuga');
$response->assertSeeText('piyo');
}
}
このように Real Time Facade はそれ自体がモックを簡単にできるようにされているので、どのメソッドがコールされ、何を返すかを指定することができる。(端折ったけど、実際のレスポンスをフィクスチャとして保持して、それを返すようにしたほうがよさそう)