PHPでTDD&CIワークショップにいってきました

PHPでTDD&CIワークショップにいってきました。スタッフのみなさん、会場を提供してくれたGREEのみなさんには感謝感謝です。

独学ながらTDDについて学んでるところなんですが、やっぱり同じ目的を持って勉強会に参加している方の手法や姿勢をみていると刺激になります。はじめてのペアプロも楽しかったです。jenkinsのセッションもすごく興味深いのであとでおさらいしてみたいですね。

さて、僕が参加したTDDセッションではおなじみのFizzBuzzをTDD手法で開発してみようというものでした。

とりあえずあの場で書きあがったコードを未完成ですが晒してみます。

fizzbuzz.php

<?php
/**
 * Generated by PHPUnit on 2011-06-20 at 21:36:50.
 */
class fizzbuzz {
  function getFizzBuzz($i) {
    if (!is_numeric($i)) throw new Exception('数値以外はだめだよ');

    if ($i % 3 === 0 && $i % 5 === 0) return 'FizzBuzz';  
    if ($i % 3 === 0) return 'Fizz';
    if ($i % 5 === 0) return 'Buzz';
    return (string) $i;
  }

  function getFizzBuzzList($from, $to = 1) {
    if (!is_numeric($from)) throw new Exception('数値以外はだめだよ');
    if (!is_numeric($to)) throw new Exception('数値以外はだめだよ');

    if ($from < $to) {
      $to = $from;
      $from = 1;
    }

    $result = array();
    for ($i = $from; $i <= $to; $i ++) {
      $result[] = $this->getFizzBuzz($i);
    }
    return $result;
  }
}

fizzbuzzTest.php

<?php

require_once dirname(__FILE__) . '/fizzbuzz.php';

/**
 * Test class for fizzbuzz.
 * Generated by PHPUnit on 2011-06-20 at 21:39:26.
 */
class fizzbuzzTest extends PHPUnit_Framework_TestCase {
  /**
   * @var fizzbuzz
   */
  protected $object;

  /**
   * Sets up the fixture, for example, opens a network connection.
   * This method is called before a test is executed.
   */
  protected function setUp() {
      $this->object = new fizzbuzz;
  }

  /**
   * Tears down the fixture, for example, closes a network connection.
   * This method is called after a test is executed.
   */
  protected function tearDown() {
  }

  function test_getFizzBuzz_引数が1のときには1() {
    $this->assertEquals('1', $this->object->getFizzBuzz(1));
  }

  // 別データでテストをすることで精度を高める
  function test_getFizzBuzz_引数が2のときには2() {
    $this->assertEquals('2', $this->object->getFizzBuzz(2));
  }

  function test_getFizzBuzz_引数が3の倍数のときはFizz() {
    # Test関数の中のassertは1つがベスト
    $this->assertEquals('Fizz', $this->object->getFizzBuzz(3));
  }

  function test_getFizzBuzz_引数が4のときには4() {
    $this->assertEquals('4', $this->object->getFizzBuzz(4));
  }

  function test_getFizzBuzz_引数が5の倍数のときはBuzz() {
    $this->assertEquals('Buzz', $this->object->getFizzBuzz(5));
  }

  function test_getFizzBuzz_引数が3の倍数かつ5の倍数のときはFizzBuzz() {
    $this->assertEquals('FizzBuzz', $this->object->getFizzBuzz(15));
  }

  function test_getFizzBuzz_引数が数字以外のときにはException() {
    try {
      $this->object->getFizzBuzz('');
      $this->fail('例外を返すつもりが反らなかったよ');
    } catch (Exception $e) {
      $this->assertEquals('数値以外はだめだよ', $e->getMessage());
    }
  }

  function test_getFizzBuzzList_引数が数字以外のときにはException() {
    try {
      $this->object->getFizzBuzzList('');
      $this->fail('例外を返すつもりが反らなかったよ');
    } catch (Exception $e) {
      $this->assertEquals('数値以外はだめだよ', $e->getMessage());
    }
  }

  function test_getFizzBuzzList_1_to_16 () {
    $expected = array(
      1,
      2,
      'Fizz',
      4,
      'Buzz',
      'Fizz',
      7,
      8,
      'Fizz',
      'Buzz',
      11,
      'Fizz',
      13,
      14,
      'FizzBuzz',
      16
    );
    $this->assertEquals($expected, $this->object->getFizzBuzzList(16));
   }

  function test_getFizzBuzzList_2_to_16 () {
    $expected = array(
      2,
      'Fizz',
      4,
      'Buzz',
      'Fizz',
      7,
      8,
      'Fizz',
      'Buzz',
      11,
      'Fizz',
      13,
      14,
      'FizzBuzz',
      16
    );
    $this->assertEquals($expected, $this->object->getFizzBuzzList(2, 16));
   }
}

これgetFizzBuzzListを呼び出した際に第2引数がある時とない時とでfrom,toがいい感じで入れ替わる…みたいな実装を考えた結果from,toの入れ替え処理が怪奇なことになってます。

先にテストありきで進めていかないとダメですね。

まだ精進が足りないです。