Posted at

Laravel 4でREST APIのテストを書いて$this->callに嵌る

More than 5 years have passed since last update.


便利な $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 は相対パスで書ける!便利!! と思いますよね。

実は、ここにはちょっとした罠がありました。


試す

まずは、普通に試してみます。

適当なルートを用意して、単純なテストを書きます。


routes.php

<?php

Route::get('test/create', function () {
return Response::make('ok');
});



APITest.php

<?php

class APITest extends TestCase {

public function testGetTest()
{
$response = $this->call('GET', 'test/create');
$this->assertTrue($response->isOk());
}
}


走り切りましたね。

テストは通りました。

では、 APITest.php の方に手を加えて、 2 回リクエストを送ってみます。

実際にこんなテストは書きませんが、何か副作用のある API を叩いた後に適用されているかチェックする意味で、 1 つのテストケースの中で 2 回以上リクエストを送りたいことがあると思います。


APITest.php

<?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 ではこのような嵌まり方はしません。


Illuminate/Foundation/Testing/TestCase.php

    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 インスタンスが新しく生成される為です。


参考


最後に

コードを追う前に Qiita やフォーラムを参照しましょう。