LoginSignup
5
0

More than 5 years have passed since last update.

PHPUnitの@dataProviderはforループの40倍遅い

Last updated at Posted at 2019-01-09

PHPUnitにはテストデータを駆動してテストケースを実行するData Providerという機能があるが、それは一つのテストケースでforループするより40倍遅い。

テストコード

検証のために次のようなテストコードを用意した。完全版はGitHubに置いてある。

UsingDataProviderTest.php
final class UsingDataProviderTest extends TestCase
{
    /**
     * @dataProvider trues
     */
    public function test_true(bool $value): void
    {
        self::assertTrue($value);
    }

    public function trues(): iterable
    {
        for ($count = 1; $count <= 1000; $count++) {
            yield [true];
        }
    }
}
UsingLoopTest.php
final class UsingLoopTest extends TestCase
{
    public function test_true(): void
    {
        foreach ($this->trues() as $value) {
            self::assertTrue($value);
        }
    }

    public function trues(): iterable
    {
        for ($count = 1; $count <= 1000; $count++) {
            yield true;
        }
    }
}

実行結果

  • UsingDataProviderTest: 474ms
  • UsingLoopTest: 12ms

40倍くらい速さが違う

なぜdataProviderは遅いか?

dataProviderの遅さの原因仮説としてはこう考えられる。dataProviderはデータごとに1テストのサイクルを回す。そのサイクルの中には、テストオブジェクトの生成やsetUptearDown、レポーティングなどさまざまな処理がある。ひとつのメソッドの中でforループするテストは、そういうオーバヘッドがないぶん早くなる。

forとdataProviderは置き換え可能というわけではない

dataProviderはデータごとに独立したテストになるので、ひとつ前のデータがFAILになっても次のデータのテストは実行される。一方、forでループした場合は、FAILになったデータでテストが止まる。こういう違いがあるので、両者は置き換え可能というわけでない点は注意する。

結論

  • 遅いと言っても、前後のデータにテスト実行計画が依存しないdataProviderのほうが普通はいい。
  • ただ、沢山のパターン(数万パターン等)を網羅してテストしたい場合は、dataProviderだと体感的につらくなるので、そういう場合はforを使ってもいいかもしれない。
5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0