便利な $this->call
Laravel ではユニットテストの中で $this->call
を呼び出すことで、簡単に HTTP リクエストを送った結果をテストすることが出来ます。
内部では Symfony\Component\HttpKernel\Client
が使われています。
ドキュメント にはこう書かれています。
You may easily call one of your routes for a test using the call method:
$response = $this->call('GET', 'user/profile'); $response = $this->call($method, $uri, $parameters, $files, $server, $content);
$uri は相対パスで書ける!便利!! と思いますよね。
実は、ここにはちょっとした罠がありました。
試す
まずは、普通に試してみます。
適当なルートを用意して、単純なテストを書きます。
<?php
Route::get('test/create', function () {
return Response::make('ok');
});
<?php
class APITest extends TestCase {
public function testGetTest()
{
$response = $this->call('GET', 'test/create');
$this->assertTrue($response->isOk());
}
}
走り切りましたね。
テストは通りました。
では、 APITest.php
の方に手を加えて、 2 回リクエストを送ってみます。
実際にこんなテストは書きませんが、何か副作用のある API を叩いた後に適用されているかチェックする意味で、 1 つのテストケースの中で 2 回以上リクエストを送りたいことがあると思います。
<?php
class APITest extends TestCase {
public function testGetTest()
{
$response = $this->call('GET', 'test/create');
$this->assertTrue($response->isOk());
$response = $this->call('GET', 'test/create');
$this->assertTrue($response->isOk());
}
}
このテストコードを走らせると、必ず 2 回目のリクエストで Symfony\Component\HttpKernel\Exception\NotFoundHttpException
が発生します。
1 回目でリクエストが通っていて、何も副作用のあることしていないのに…どうして NotFound !? と困惑します。
結論
$uri
は /
から書く。
つまり
$response = $this->call('GET', '/test/create');
こう書けば、何度でも呼び出せます。
$this->call
に $uri
を相対 URI で渡すと、前回リクエストした URI からの相対 URI になるようで、それは NotFound になるのも納得できます。
ちなみに、 $this->call
の HTTPS 版である $this->callSecure
ではこのような嵌まり方はしません。
public function callSecure()
{
$parameters = func_get_args();
$parameters[1] = 'https://localhost/'.ltrim($parameters[1], '/');
return call_user_func_array(array($this, 'call'), $parameters);
}
https://localhost/
決め打ちな所がカジュアルですね。
備考
Laravel のフォーラム にはこんなことが書いてありました。
Doing a $this->refreshApplication() fixes it, just ensure that you set up the test again.
$this->call
呼んだ後に毎回 $this->refreshApplication
を呼ばないといけないなんて、そんな非効率なことある訳ないですね。
$this->refreshApplication
を呼ぶと直るのは、 Client
インスタンスが新しく生成される為です。
参考
- テスト | Symfony2日本語ドキュメント
- TestCase::call()
- Symfony\Component\HttpKernel\Client
- Symfony\Component\BrowserKit\Client getAbsoluteUri()
最後に
ドキュメントに書いてないのなら、コードを読むまでだ…
— たけ@日常 (@ww24) September 1, 2014
コードを追う前に Qiita やフォーラムを参照しましょう。