2018.08.08 PHPUnitのdataProviderを使ったらrisky testになった話

PHPの単体テストをするときに使われているフレームワークにPHPUnitというやつがありますが、dataProviderという機能を使うとテスト部分とテストに使うパラメータが分離できていいぞということを聞いたので使ってみることにしました。

dataProviderを使う場合は、dataProviderを使用するメソッドのPHPDocに@dataProviderというアノテーションを書くそうなので、下のプログラムを書いて実行してみました。

<?php

class hoge
{
    public function func($x)
    {
        return $x;
    }
}
<?php

use PHPUnit\Framework\TestCase;
require_once 'hoge.php';

class HogeTest extends TestCase
{
    private $hoge;

    protected function setUp()
    {
        $this->hoge = new Hoge();
    }

    /**
     * @dataProvider testFuncProvider
     */
    public function testFunc($x)
    {
        $this->assertEquals($this->hoge->func($x), $x);
    }

    public function testFuncProvider()
    {
        return [
            'success 1' => [1],
            'success 3' => [3],
            'success 8' => [8],
        ];
    }
}

すると、下のようにPHPUnitのassertを使ってないぞ!(This test did not perform any assertions)と怒られてしまいました。

どうやらdataProvider用に作ったメソッドがPHPUnitのテスト対象にも入ってしまっているのが原因だったのでPHPUnitのドキュメントを見直してみたところ、testという名前から始まるpublicなメソッドは自動的にPHPUnitのテスト対象になってしまうようでした。
そのため、単体テスト用のクラスを以下のように書き直すことでテストが正しく動くようになりました。

<?php

use PHPUnit\Framework\TestCase;
require_once 'hoge.php';

class HogeTest extends TestCase
{
    private $hoge;

    protected function setUp()
    {
        $this->hoge = new Hoge();
    }

    /**
     * @dataProvider funcProvider
     */
    public function testFunc($x)
    {
        $this->assertEquals($this->hoge->func($x), $x);
    }

    public function funcProvider()
    {
        return [
            'success 1' => [1],
            'success 3' => [3],
            'success 8' => [8],
        ];
    }
}

これがなかなか分からずに、「どうやってもリスキーなテストしか書けないのかーっ!」と思ってましたが、ドキュメントをちゃんと読みなさいって話ですね・・・