[Laravel]ユニットテストをする(phpunit設定など)

Laravel

Laravelでテストを書く方法について、記載しています。
前に作ったLaravelの掲示板にテストを入れてみました。

下記はLaravel5で確認しています。

ユニットテストを作成する

ユニットテストを作成するときは下記のコマンドを使用します。
CreateMakeBoardCaseTestがテストのクラス名になります。 –unitをつけることでユニットテストのファイルができます。

php artisan make:test CreateMakeBoardCaseTest --unit

できたファイルを確認する

tests/Unit/にファイルが作成されるので、開いてみます。
TestCaseクラスを継承した、指定した名前のクラスが作成されてテストケースがひとつだけ用意されています。

class CreateMakeBoardCaseTest extends TestCase
{
    /**
     * A basic unit test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->assertTrue(true);
    }
}

ファイルを修正する

下記のようにファイルを修正してみました。

class CreateMakeBoardCaseTest extends TestCase
{
    public function testRegister()
    {
        Board::truncate();

        $createMakeBoardCase = new CreateMakeBoardCase();
        $createResult = $createMakeBoardCase->__invoke('boardTitleTest', 'boardUserNameTest', 'boardAboutTextTest', 'boardPasswordTest');

        $board = Board::where('title', 'boardTitleTest')->first();

        $this->assertTrue($createResult);
        $this->assertEquals('boardTitleTest', $board->title);
        $this->assertEquals('boardUserNameTest', $board->user_name);
        $this->assertEquals('boardAboutTextTest', $board->about_text);
        $this->assertEquals('boardPasswordTest', $board->password);
    }
}

元々のtestExampleは削除して、testRegister(登録のテスト)メソッドを作りました。
メソッド名については「test」で始まるメソッド名でないと、テストできないようです。

内容はBoard::truncateで掲示板テーブルを空にして、
usecaseをnewして新しくテーブルにインサートしています。

インサートされた値を取り出して、取り出した値がインサート時のパラメータと同じかテストしています。

テスト用のデータベースを使うようにする

そのままテストを走らせると、アプリで使っているデータベースが更新されるので
画面から登録した値と、テストで消したり入れたりする値が混在してしまいます…

なので、別のデータベースを用意してテストするように設定します。
下記の3つの方法を試してみました。

sqliteのdatabaseを別に作ってテスト用に設定する

別のsqliteファイル(database)を作成して、テストをします。

phpunitを修正する

phpunit.xmlを下記のように修正します。

<php>
    <server name="APP_ENV" value="testing"/>
    <server name="BCRYPT_ROUNDS" value="4"/>
    <server name="CACHE_DRIVER" value="array"/>
    <server name="MAIL_DRIVER" value="array"/>
    <server name="QUEUE_CONNECTION" value="sync"/>
    <server name="SESSION_DRIVER" value="array"/>
    <server name="DB_CONNECTION" value="sqlite"/>
    <server name="DB_DATABASE" value="./database/testing.sqlite"/>
</php>

DB_CONNECTIONはsqliteにして、DB_DATABASEにファイルまでの相対パスで設定しました。

.env.testingファイルを作成する

テストする前にmigrationをしないといけないので、
test用のデータベースの設定などを書いた.env.testingファイルを作成してmigrateを実行します。

ファイルの内容は、下記以外は使っていた.envと同じようにします。

DB_CONNECTION=sqlite
DB_DATABASE=./database/testing.sqlite

テスト用のデータベースにmigrationする

設定後、envファイルを指定して、migrateを流すとテスト実行環境出来上がりです。
テストした結果はマイグレーションしたデータベースに残ります。

php artisan migrate --env=testing

sqliteのインメモリ機能を使ってテスト用に設定する

sqliteのインメモリ機能を使って、データベースを作成せずにテストをしたい場合は、それぞれのファイルを編集しテストケースも工夫する必要があります。

phpunit.xmlを編集する

phpunit.xmlを下記のように編集します。
DB_CONNECTIONのvalueの箇所をconfigに新しく追加する設定に変えます。

<php>
    <server name="APP_ENV" value="testing"/>
    <server name="BCRYPT_ROUNDS" value="4"/>
    <server name="CACHE_DRIVER" value="array"/>
    <server name="MAIL_DRIVER" value="array"/>
    <server name="QUEUE_CONNECTION" value="sync"/>
    <server name="SESSION_DRIVER" value="array"/>
    <server name="DB_CONNECTION" value="sqlite_testing"/>
</php>

config/database.phpを編集する

config/database.phpのファイルを開きます。データベースの接続設定が定義されているので下記のように修正します。

sqlite_testingの項目を増やして、
driverがsqlite, databaseが:memory:, prefixなしで設定します。

'connections' => [
    'sqlite_testing' => [
        'driver' => 'sqlite',
        'database' => ':memory:',
        'prefix' => '',
    ],

テストケースを編集する

インメモリでテストする場合の注意点は、メモリ上にデータベースが用意されているわけではないので
テスト毎に毎回データベースをメモリ上に用意する必要があるようです。データベースが用意されている前提で動かすとエラーになります。

下記のようにuse DatabaseMigrationsトレイトを入れるようにします。
そうすると、migrate:freshが毎回呼ばれて、データベースクリアされます。
テーブルはデータベースに残りません。

class CreateMakeBoardCaseTest extends TestCase
{
    use DatabaseMigrations;

    public function testRegister()
    {
        Board::truncate();

        $createMakeBoardCase = new CreateMakeBoardCase();
        $createResult = $createMakeBoardCase->__invoke('boardTitleTest', 'boardUserNameTest', 'boardAboutTextTest', 'boardPasswordTest');

        $board = Board::where('title', 'boardTitleTest')->first();

        $this->assertTrue($createResult);
        $this->assertEquals('boardTitleTest', $board->title);
        $this->assertEquals('boardUserNameTest', $board->user_name);
        $this->assertEquals('boardAboutTextTest', $board->about_text);
        $this->assertEquals('boardPasswordTest', $board->password);
    }
}

mysqlのdatabaseを別に作ってテスト用に設定する

phpunit.xmlを修正する

DB_CONNECTIONの箇所をmysqlにします。

<php>
    <server name="APP_ENV" value="testing"/>
    <server name="BCRYPT_ROUNDS" value="4"/>
    <server name="CACHE_DRIVER" value="array"/>
    <server name="MAIL_DRIVER" value="array"/>
    <server name="QUEUE_CONNECTION" value="sync"/>
    <server name="SESSION_DRIVER" value="array"/>
    <server name="DB_CONNECTION" value="mysql"/>
</php

.env.testingを作成する

.envをコピーして、.env.testingを作成します。 APP_ENVの設定値がtestingになっているので、.env.testingというファイル名になります。
テスト用データベースに接続するための情報を設定します。

DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=sample_db
DB_USERNAME=root
DB_PASSWORD=password

テスト用のデータベースにmigrationする

設定後、envファイルを指定して、migrateを流すとテスト実行環境出来上がりです。
テストした結果はマイグレーションしたデータベースに残ります。

php artisan migrate --env=testing

作ったテストを実行する

全体のテストをする

下記のようにcomposerでインストールされた、phpunitを呼ぶとテストができます。

./vendor/bin/phpunit

ファイル単位でテストする

ファイルを指定するとファイル単位でのテストができます。

./vendor/bin/phpunit tests/Unit/CreateMakeBoardCaseTest.php

結果は下記のような感じで出力されます。

$ ./vendor/bin/phpunit
PHPUnit 7.5.9 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 374 ms, Memory: 18.00 MB

OK (2 tests, 6 assertions)

コメント

タイトルとURLをコピーしました