【Laravel】PHPUnitでControllerの自動テストを実装する

Laravel PHPUnitでControllerの自動テストを実装する

こんにちは。

バックエンドエンジニアのほんちゃんです。

honchan

エンジニア

ほんちゃん

暑くて外出しにくい日々ですが、運動不足解消のため、休日は室内でも出来る運動を試行錯誤中です。

honchan

エンジニア

ほんちゃん

過去に何回か当ブログの記事に登場していますが、今回は自身で記事を執筆したいと思います。

honchan

エンジニア

ほんちゃん

 

 

さて、本題に入ります。

今回はLaravelとPHPUnitでControllerのテストケースを紹介したいと思います。

皆さんはアプリケーション開発時、どのような手法でテストを実施しているでしょうか?

Selenium等で自動テストを実施などがあると思いますが、手作業で実施しているケースもあったりするのではないでしょうか。 そのような環境にも導入しやすいテストケースから考えていきたいと思います。

Laravelで製造したアプリケーションとPHPUnitで自動テストを実施する方法を紹介します。

honchan

エンジニア

ほんちゃん

環境

・PHP 8.1.9

・Laravel Framework 9.25.1

・PHPUnit 9.5.21

テストケース(成功例)

Controller概要

例として、次のようなControllerを作成しました。

・DBからInformationのレコードを取得する。

・ViewにInformationの数をセットする。

・画面タイトルとInformationの数を出力したViewを返す。

ソースコードは下記です。

// app\Http\Controllers\InformationController.php
namespace App\Http\Controllers;

use App\Models\Information;
use Illuminate\View\View;

class InformationController extends Controller
{
    public function getIndex(): View
    {
        $information = Information::orderBy('created_at')->limit(10)->get();

        return view('information.index', ['information_count' => $information->count()]);
    }
}
// resources\views\information\index.blade.php
Information Count
count: {{ $count }}

上記を実行すると画面には下記のように表示されます。

Information Count
count: 9 

タイトルと件数を表示するだけの非常にシンプルなページですね。

PHPUnitで、これらに対するテストケースを書いてみます。

honchan

エンジニア

ほんちゃん

// tests\Feature\InformationControllerTest.php
namespace Tests\Feature;

use Tests\TestCase;

class InformationControllerTest extends TestCase
{
    /**
     * @test
     */
    public function getIndex()
    {
        $response = $this->get(route('information.index'));

        $response->assertOk();

        $response->assertViewIs('information.index');

        $response->assertViewHas(['count' => 10]);

        $response->assertSeeText('Information');
        $response->assertSeeText('count: 10');
    }
}

実行と結果

上記のテストケースを実行します。

# vendor/bin/phpunit

下記のように表示されれば、テスト成功です。

テストケース説明

テストが通ったところで、テストの内容を説明していきます。

先ほどのソースコードから該当箇所のみ抜粋しました。

honchan

エンジニア

ほんちゃん

// まず、テスト対象ページを取得します。
$response = $this->get(route('information.index'));

// ページに正常にアクセス出来ることをテストします。
// HTTPステータスコード200が返ってきていることを確認します。
$response->assertOk();

// 指定のViewを読み込んでいることをテストします。
$response->assertViewIs('information.index');

// View変数をセットしているかテストします。
$response->assertViewHas(['count' => 10]);

// ページの中に指定の文字列が存在するかテストします。
$response->assertSeeText('Information');
$response->assertSeeText('count: 10');

ここまでで、Controllerとそれに対するテストケースの実装が出来ました。

次に、このテストケースを使って不具合を発見する例を書きたいと思います。

作り終わってから修正が全く入らないプログラムは少なく、殆どの場合、後から何らかの追加修正や不具合修正が入ると思います。

既に作成済みのプログラムが正常に動くことを注意しつつ、修正を行うことは多いのではないでしょうか。

このような場合、上記で作成したテストケースが役に立ちます。

テストケース(失敗例)

次に不具合を検知する例を書きたいと思います。

先ほどのControllerを一部変更しました。

limit(10)がlimit(9)になっています。

// app\Http\Controllers\InformationController.php
class InformationController extends Controller
{
    public function getIndex(): View
    {
        // limit(9)に修正しました。
        $information = Information::orderBy('created_at')->limit(9)->get();

        return view('information.index', ['information_count' => $information->count()]);
    }
}

実行と結果

このような状態でテストケースを実行すると、下記の結果になります。

行番号が表示されているので、下記のテストケースが失敗したことがわかります。

$response->assertViewHas(['count' => 10]);

上記のように、テストケースが期待する結果にならない場合はテストを通らないため、不具合等の発見が容易になります。

honchan

エンジニア

ほんちゃん

Controllerの中では、Sessionを使用することも多いと思いますがそれらに対してもテストが可能です。

honchan

エンジニア

ほんちゃん

最後に

今回はLaravelのControllerに対して、基本的なテストを書いてみました。
PHPUnitはLaravelに限らずPHPで製造したアプリケーションであれば、ほぼ導入可能かと思います。

テストケースを書くことで、不具合修正やリファクタリング時に発生した不具合を検知しやすくなります。
実際のアプリケーションはController以外の要素も登場しますが、それらに対するテスト方法も存在します。
(Model、Routing、認証など)

次回からは、Controller以外のテストや、テスト観点(テストケースの考え方)などを紹介していきたいと思います。

 

ロジカルスタジオではエンジニアを募集しています。

今回使ったLaravelやPHPUnitなど、バックエンド技術を使って開発がしてみたいという方は、是非採用サイトからご応募ください!