PHP
laravel

Laravel ルート定義を取得して一括でHTTPテストする。

ルート定義を取得して一括でHTTPテスト、ステータス200が返ってくるかチェックする。
個別にパラメータを定義しておけばパラメータ付きURLのチェックも可能。
基本的に更新系のページは除外。
※Laravelの認証機能を使っている前提で組んであります。

$ php artisan make:test EasyTest
tests/Feature/EasyTest
<?php

namespace Tests\Feature;

use Tests\TestCase;
use \Route;
use App\User;

class EasyTest extends TestCase
{
    private static $user;

    /*
     * 除外設定
     */
    private $easy_route_exclude = [
        '/edit',
        '/reset',
        '/delete',
        '/update',
        '/insert',
        '/login',
        '/logout',
    ];

    /*
     * パラメータ設定
     */
    private $easy_route_params = [
        '[uri]' => [
            [
                '[param_name]' => [param_value],
            ],
        ],
    ];

    public function testGuestLogin()
    {
        $this->get('/')->assertRedirect('login');
    }

    public function testLogin()
    {
        $this->withoutExceptionHandling();
        $response = $this->get('/login');
        $response->assertStatus(200);
    }

    public function testGetUser()
    {
        $this->withoutExceptionHandling();
        self::$user = User::orderBy('id', 'asc')->limit(1)->first();
        $this->assertNotEmpty(self::$user);
    }

    public function testEasyRouteCheck()
    {
        // Route::getRoutes()のデータ量が多いため適当にmemory_limitを変える
        ini_set('memory_limit', '2048M');

        $this->withoutExceptionHandling();
        $check_uri = [];
        $check_method = ['GET', 'POST'];
        $routes = Route::getRoutes()->getRoutesByMethod();
        foreach ($check_method as $method) {
            foreach ($routes[$method] as $v) {
                $uri = $v->uri();
                if ($uri === '/') {
                    continue;
                } else {
                    $uri = '/' . $uri;
                }
                $check = true;
                foreach ($this->easy_route_exclude as $c) {
                    if (strpos($uri, $c) !== false) {
                        $check = false;
                    }
                }
                if ($check === true) {
                    $check_uri[$method][] = $uri;
                }
            }
        }
        foreach ($check_uri as $method => $uris) {
            foreach ($uris as $uri) {
                if ($method === 'POST') {
                    if (isset($this->easy_route_params[$uri])) {
                        $params = $this->easy_route_params[$uri];
                        foreach ($params as $k => $p) {
                            $response = $this->actingAs(self::$user)->post($uri, $p);
                            $response->assertStatus(200);
                        }
                    }
                } else {
                    $response = $this->actingAs(self::$user)->get($uri);
                    $response->assertStatus(200);
                    if (isset($this->easy_route_params[$uri])) {
                        $params = $this->easy_route_params[$uri];
                        foreach ($params as $p) {
                            $param_uri = $uri . '?' . http_build_query($p);
                            $response = $this->actingAs(self::$user)->get($param_uri);
                            $response->assertStatus(200);
                        }
                    }
                }
            }
        }
    }
}

テストを実行

$ vendor/phpunit/phpunit/phpunit

もしくは

$ vendor/phpunit/phpunit/phpunit tests/Feature/EasyTest

テスト前に$this->withoutExceptionHandling()を実行しておかないと、テスト対象のスクリプト内でExceptionが発生してもスルーされる。
しかも$response->assertStatus(200)が通ってしまう。
Webサーバーはステータス500を返しているはずなんだけど、$response->getStatusCode()は200を返す。
この挙動でハマってしまった。
エラーの時に何かするというテストでなければ$this->withoutExceptionHandling()を入れておいた方がようさそう。