s_tajima:TechBlog

渋谷で働くインフラエンジニアのTechブログです。

PHPUnitのデータプロバイダの使い方

以下のような映画館の料金判定のメソッドに対して、テストを書くことを想定。

  • 12歳以下と13歳以上で、子供料金と大人料金を区別する
    • 子供料金:1000円、大人料金:1800円
  • 男性と女性を区別する
    • 毎週水曜日をレディースデーに設定し、女性であれば料金を半額にする

実装

<?php
class Movie {
    function check($gender, $age, $date){
        date_default_timezone_set('Asia/Tokyo');

        //入力値が期待されているものかのチェック
        if ($gender !== "man" && $gender !== "woman") return false;
        if (!is_int($age) || $age < 0) return false;

        $date = explode('/', $date);
        if(!checkdate($date[1], $date[2], $date[0])) return false;

        $price = ($age <= 12) ? 1000 : 1800; 
        if($gender === "man") return $price;

        $weekday = date("l", mktime(10, 10, 10, $date[1], $date[2], $date[0]));
    
        if($weekday === "Wednesday") $price = $price/2;
        return $price;
    }   
} 

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

<?php
require_once "./Movie.php";

class MovieTest extends PHPUnit_Framework_TestCase
{   
    public function setup()
    {   
        $this->Movie = new Movie();
    }   

    public function testMovie()
    {   
        #男性のテスト
        $this->assertEquals(1000, $this->Movie->check('man', 12, '2012/05/15'));
        $this->assertEquals(1800, $this->Movie->check('man', 13, '2012/05/15'));
        $this->assertEquals(1000, $this->Movie->check('man', 12, '2012/05/16'));
        $this->assertEquals(1800, $this->Movie->check('man', 13, '2012/05/16'));

        #女性のテスト
        $this->assertEquals(1000, $this->Movie->check('woman', 12, '2012/05/15'));
        $this->assertEquals(1800, $this->Movie->check('woman', 13, '2012/05/15'));
        $this->assertEquals(500, $this->Movie->check('woman', 12, '2012/05/16'));
        $this->assertEquals(900, $this->Movie->check('woman', 13, '2012/05/16'));

        #例外のテスト
        $this->assertEquals(false, $this->Movie->check('men', 12, '2012/05/15'));
        $this->assertEquals(false, $this->Movie->check('man', -1, '2012/05/15'));
        $this->assertEquals(false, $this->Movie->check('man', 12, '2012/15/15'));
    }   
}

これをデータプロバイダを使うとこうなる

<?php
require_once "./Movie.php";

class MovieTest extends PHPUnit_Framework_TestCase
{   
    public function setup()
    {   
        $this->Movie = new Movie();
    }   

    public static function patternProvider()
    {   
        $values = array(
            array(1000,  'man',   12, '2012/05/15'),
            array(1800,  'man',   13, '2012/05/15'),
            array(1000,  'man',   12, '2012/05/16'),
            array(1800,  'man',   13, '2012/05/16'),
            array(1000,  'woman', 12, '2012/05/15'),
            array(1800,  'woman', 13, '2012/05/15'),
            array(500,   'woman', 12, '2012/05/16'),
            array(900,   'woman', 13, '2012/05/16'),
            array(false, 'men',   12, '2012/05/15'),
            array(false, 'man',   -1, '2012/05/15'),
            array(false, 'man',   12, '2012/15/15'),
        );  
        return $values;
  }

    /** 
     * @dataProvider patternProvider
     */
    public function testMovie($price, $gender, $age, $date)
    {   
        $this->assertEquals($price, $this->Movie->check($gender, $age, $date));
    }
}  
データプロバイダの使い方なのでプログラムの仕様とかテストケースとかにはふれないで...