LoginSignup
14
11

More than 5 years have passed since last update.

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

Posted at

便利な $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 やフォーラムを参照しましょう。

14
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
11