Laravelテストで、DataProvider/データプロバイダーの使い方

LaravelのテストでDataProviderを使っていますでしょうか。今回は、DataProviderとは。効果について述べていきます。

0-1. DataProviderとは

Laravel Unitテストにおけるテスト用のデータを生成する仕組みです。Unitテストには、様々なデータ生成の仕組みが存在します。そのうちの1つです。

0-2. DataProviderのメリット

では、様々なデータ生成の仕組みが存在するなかで、DataProviderのメリットはなんでしょうか。それは同じテストにおいて、データのみが異なる場合に非常に簡単に実行してくれます。

例えば、動物かどうかを確認するテスト を実行する際に。
確認するデータ(猿・像・ひまわり・ライオン ) に対して毎回テストを書いていたら面倒ですよね?? これをDataProviderを使えば簡単に全データをテストしてくれます。

1. DataProviderの書き方

1-1. DataProviderのメソッドを書く

> tests/AnimalTest.php

public function test_check_animal(){
//実行されるテスト
}


//これがDataProviderです。
public function animalTestData(){
        return [
            '猿'       => ['肺呼吸', 'move', '光合成ナシ'],
            '像'       => ['肺呼吸', 'move', '光合成ナシ'],
            'ひまわり'  => ['気孔と樹皮', 'stay', '光合成アリ'],
            'ライオン'  => ['肺呼吸', 'move', '光合成ナシ'],
        ];
}

注意点

  1. アクセス修飾子は public
  2. returnの中は連想配列で

1-2. DataProviderをテストメソッドで呼び出す

public function test_check_animal() でDataProviderを使ってみます。

> tests/AnimalTest.php

/**
 * @dataProvider animalTestData
 */
public function test_check_animal(string $breathing, string $move, bool $photosynthesis){
//実行されるテスト

}


//これがDataProviderです。
public function animalTestData(){
        return [
            '猿'       => ['肺呼吸', 'move', '光合成ナシ'],
            '像'       => ['肺呼吸', 'move', '光合成ナシ'],
            'ひまわり'  => ['気孔と樹皮', 'stay', '光合成アリ'],
            'ライオン'  => ['肺呼吸', 'move', '光合成ナシ'],
        ];
}

注意点

  1. DataProviderを利用するテストメソッドの上で、利用するDataProviderを宣言します。
    • @dataProvider animalTestData で宣言している部分です。
  2. テストメソッドでDataProviderのデータを引数で受け取ります。
    • string $breathing, string $move, bool $photosynthesis で引き受けている部分です。

以上です。

猿・像・ひまわり・ライオン の4種類のテストが1つのテストメソッドで実行出来ます。

UnitTest/Laravel5.xから6.xへ変更 | Method ‘XXXX’ is not compatible with method ‘Tests\TestCase::setUp()’.intelephense(1038)

Laravel5.xから6.x へバージョン変更した際に発生したUnitテストのError対処法です。

1. Errorメッセージ

Method 'XXXX' is not compatible with method 'Tests\TestCase::setUp()'.intelephense(1038)

2. Error箇所

    public function setUp(){ // ここでError
        parent::setUp();
    }

3. Errorの意味

'Tests\TestCase::setUp()'と互換性がありません。

どういうことでしょうか?

setUp関数は、use Tests\TestCase; クラスから参照されています。(正確には、更に継承先ののvendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php

ここで記述されている setUp関数を確認すると。

    protected function setUp(): void
    {
         //省略
    }

返り値 void が必須になっています。

4. 修正方法

    public function setUp(): void{ // 返り値を継承先に合わせる
        parent::setUp();
    }

setUp()関数の返り値の型を継承先に合わせてあげます。

これで解決します。

Laravel:privateメソッドに対してUnitテストを実施する方法

privateメソッドに対してUnitテストを実施する方法を紹介します。

0. 前提知識

アクセス修飾子をご存知でしょうか。 class内のメソッド・プロパティに対して外部からのアクセス要件を設定する情報です。public, protected, private とあります。 privateは同一Classからしかアクセス出来ません。

つまり、Unitテストは他のClassから実行するものなので、通常のUnitテストではprivateメソッドに対してテストは実行出来ません。

では、どうやってUnitテストを実施していくのでしょうか。

Laravelには、privateメソッドに対してUnitテストを実行できる環境が用意されているので、そちらを使います。

1. ReflectionClassを利用する

実装方法は非常にシンプルです。

ExampleService内にあるprivateMehtod をUnitテストのPrivateMethodTest で実行します。

ExampleService はざっくりと下記

<?php
class ExampleService 
{
    //省略
    private function privateMehtod() // privateメソッドである
    {
        // メソッド内処理
        return $result;
    }
    //省略
}

UnitテストPrivateMethodTest は下記です。 ReflectionClass の使い方を参照下さい。 下記にて、test_example() にてprivateMehtod を実行してreturnを返しています。

<?php

use ReflectionClass;
use ExampleService;

class PrivateMethodTest extends TestCase
{
    private $reflection;
    private $service;

    public function setUp()
    {
        parent::setUp();
        $this->service = new ExampleService();
        $this->reflection = new ReflectionClass($this->service);
    }

    public function test_example()
    {
        $example_class = new ExampleService();

        $method = $this->reflection->getMethod( 'privateMehtod' );
        $method->setAccessible( true );
        $result = $method->invoke( $this->service );
        // assertでTest確認
        // 省略
    }
}

2. privateメソッドに引数がある場合

privateMehtod に引数 $params がある場合

<?php
class ExampleService 
{
    //省略
    private function privateMehtod( $params ) // privateメソッドである
    {
        // メソッド内処理
        return $result;
    }
    //省略
}

変更箇所で記述しています。

  • invoke( ) -> invokeArgs( )
  • invokeArgs( ) の第2引数に$params を代入
    • 第2引数 は array型で渡す必要があります。
<?php

use ReflectionClass;
use ExampleService;

class PrivateMethodTest extends TestCase
{
     // 省略

    public function test_example()
    {
        // 省略
        $result = $method->invokeArgs( $this->service, [$params] );
        // 省略
    }
}

以上です。

ReflectionMethodを使う方法もありますが、今回はReflectionClass を使う方法を紹介しました。

Laravel5.2でのUnitテスト実行コマンド

物凄くニッチなテーマですが。

Readoubleにもコマンドが書かれていなかったので、備忘録です。

1. アプリフォルダへ移動

2. testsディレクトリ全てのテストを実行

./vendor/bin/phpunit

3. 特定ファイルのテストを実行

./vendor/bin/phpunit tests/テストのファイル名