Tech Blog

グローバルな家族アプリFammを運営するTimers inc (タイマーズ) の公式Tech Blogです。弊社のエンジニアリングを支える記事を随時公開。エンジニア絶賛採用中!→ https://timers-inc.com/engineering

データプロバイダーを使用してテストコードを DRY に

今年の 8 月から入社したサーバーサイドエンジニアのズッキーです。主に PHPAPI サーバーの開発を担当しています。

この記事では PHPUnit で気軽に行えるテストコードのリファクタリング手法の 1 つをご紹介いたします。基礎的な内容ではありますが、明日から使えると思いますのでご存知でない方の参考になれば幸いです。

データプロバイダーとは

PHPUnit にはデータプロバイダーというテストケースに渡すデータのセットを定義できる機能があります。文章での説明よりもサンプルコードの方が分かりやすいため、下記にサンプルコードをご紹介します。

例えば、下記のような Sample クラスがあったと仮定します。calculate メソッドは第1引数の $a が 9 以下の場合は $a$b の足し算を行い、10 以上の場合は $a$b の掛け算を行います。

<?php

class Sample
{
  public function calculate($a, $b)
  {
    if($a > 9){
      $result = $a * $b;
    } else {
      $result = $a + $b;
    }
    return $result;
  }
}

このメソッドに対して、$a が 9 以下の場合と、10 以上の場合のテストを作成します。

<?php

require_once './Sample.php';

class SampleTest extends PHPUnit_Framework_TestCase
{
  public function testCalculateReturnValidResult()
  {
    $sample = new Sample();
    $actual = $sample->calculate(9, 2);
    $expected = 11;
    $this->assertSame($expected, $actual);

    $actual = $sample->calculate(10, 2);
    $expected = 20;
    $this->assertSame($expected, $actual);
  }
}

calculate メソッドには 2 パターンの引数を渡してテストを行っているため、assertSame メソッドを 2 回記述してテストを行っています。

今回の場合、引数と期待する返り値の組み合わせを差し替えるだけのテストを行っているため、データプロバイダーを使用することで、テストコードを削減することができます。

<?php

require_once './Sample.php';

class SampleTest extends PHPUnit_Framework_TestCase
{
  /**
   * @dataProvider dataProviderForCalculate
   */
  public function testCalcurationReturnValidResult($a, $b, $expected){
    $sample = new Sample();
    $actual = $sample->calculate($a, $b);
    $this->assertSame($expected, $actual);
  }

  public function dataProviderForCalculate()
  {
    return [
      [9, 2, 11],
      [10, 2, 20],
    ];
  }
}

使い方

データプロバイダーの使い方は下記のとおりです。

  • データプロバイダーとして動作するメソッドを作成します。データプロバイダーとして定義したメソッドはデータの組み合わせの配列を返すようにします。前述の例では、1 回目のテストでは [9, 2, 11] が、2 回目のテストでは [10, 2, 20] が渡され、合計 2 回のテストが実行されます。
  • アノテーションを使用して、データプロバイダーとして使用したいメソッド名を指定します。アノテーションとはメソッド定義のすぐ上に書かれている下記のようなコメントを指します。
  /**
   * @dataProvider <データセットを提供するメソッド名>
   */
  • テストを実行するメソッドには、データプロバイダーの返り値と同じ順番で引数を定義します。

テストが失敗した際の表示

例えば、2 つ目の assertSame() が失敗した場合の結果は下記の違いがあります。

データプロバイダーを使用しない場合

PHPUnit 6.3.1 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 79 ms, Memory: 8.00MB

There was 1 failure:

1) SampleTest::testCalculateReturnValidResult
Failed asserting that 20 is identical to 21.

/Users/mac/tmp/techblog/SampleTest.php:17

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.

データプロバイダーを使用した場合

PHPUnit 6.3.1 by Sebastian Bergmann and contributors.

.F                                                                  2 / 2 (100%)

Time: 81 ms, Memory: 8.00MB

There was 1 failure:

1) SampleTest::testCalcurationReturnValidResult with data set #1 (10, 2, 21)
Failed asserting that 20 is identical to 21.

/Users/mac/tmp/techblog/SampleTest.php:15

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

データプロバイダーを使用した場合、1 つのデータのセットが 1 テストケースと見なされ、何番目のテストケースが失敗したのかが表示されるようになります。(データプロバイダーとして渡した配列は #0 から始まるため、#1 は 2 番目ということになります。)

データプロバイダーを利用するメリット

  • どのアサーションメソッドで失敗したのかが分かりやすくなります。
  • テストしたい引数や返り値の組み合わせが増えた場合、データプロバイダーのデータセットを追加するだけで対応できます。テストするパターンが増えるたびに、テストコードが増長することを防ぐことができます。

積極採用中!!

子育て家族アプリFamm、カップル専用アプリPairyを運営するTimers inc. では、現在エンジニアを積極採用中! 急成長中のサービスの技術の話を少しでも聞いてみたい方、スタートアップで働きたい方など、是非お気軽にご連絡ください! 採用HP : http://timers-inc.com/engineerings

Timersでは各職種を積極採用中!

急成長スタートアップで、最高のものづくりをしよう。

募集の詳細をみる