TDD(テスト駆動開発)でFizzBuzz問題を解いてみる

# はじめに

以下本を読みながら初めてテストファーストでプログラムを書いてみました。
いきなり難しいお題だと着地しないかも、と不安だったので、誰でも知ってるFizzBuzz問題を採用してます。
なお、参考にした本は下記です。
(書籍内ではボーリングのスコア計算をTDDで扱っています。いきなりこれだとちょっとできるか不安でしたw)

[参考][これからはじめるTDD テスト駆動開発入門 ThinkIT Books](https://www.amazon.co.jp/%E3%81%93%E3%82%8C%E3%81%8B%E3%82%89%E3%81%AF%E3%81%98%E3%82%81%E3%82%8BTDD-%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-ThinkIT-Books-%E5%90%89%E8%B0%B7-ebook/dp/B00VFQ7WCM/ref=sr_1_1?ie=UTF8&qid=1501573910&sr=8-1&keywords=TDD)

# 環境

以前こちらにまとめているのと同様の環境を利用しています。

[参考][Dockerを使い手軽にPHPUnitをはじめる](http://qiita.com/masayuki5160/items/b305d5a19f3ec632f3e3)

# FizzBuzz問題
要件としては以下です。

- 3で割り切れる時は「Fizz」
- 5で割り切れる時は「Buzz」
- 3と5で割り切れる時は「FizzBuzz」と出力する

[参考][Fizz-Buzz問題](http://d.hatena.ne.jp/keyword/Fizz-Buzz%CC%E4%C2%EA)

# プログラム
テストコードは以下。

```php
<?php

require_once __DIR__. '/fizzBuzz.php';

class testFizzBuzz extends PHPUnit_Framework_TestCase
{
    private $fizzBuzz;

    public function setUp()
    {
        $this->fizzBuzz = new fizzBuzz();
    }

    public function testFizz()
    {
        $input = 3;
        $expected = "Fizz";
        $this->assertEquals($this->fizzBuzz->judge($input), $expected);
    }

    public function testBuzz()
    {
        $input = 5;
        $expected = "Buzz";
        $this->assertEquals($this->fizzBuzz->judge($input), $expected);
    }

    public function testFizzAndBuzz()
    {
        $input = 15;
        $expected = "FizzBuzz";
        $this->assertEquals($this->fizzBuzz->judge($input), $expected);
    }
}
```

プログラムはこちらです。

```php
<?php

class fizzBuzz
{
    public function judge($input)
    {
        $result = $input;
        if($input % 3 == 0 && $input % 5 == 0){
            $result = "FizzBuzz";
        }elseif($input % 3 == 0){
            $result = "Fizz";
        }elseif($input % 5 == 0){
            $result = "Buzz";
        }

        return $result;
    }
}
```

# 所感
本を読みながら見よう見真似でトライしてみたので本当にTDDになっているのかあれですが、

- テストファーストで取り組むとコードを書くのが楽しい(RED、GREENな状態を繰り返し、仕上げるプロセスがいい)
- 今までと明らかに違う考え方、設計の仕方になる(設計力のアップに繋がる気がした)

というのは感じました。
ただ、これは取り上げた問題がFizzBuzzだったせいかもしれませんが、実は最終的にテストコードは下記がいいかなと修正したりしてました。

```php
<?php

require_once __DIR__. '/fizzBuzz.php';

class testFizzBuzz extends PHPUnit_Framework_TestCase
{
    private $fizzBuzz;

    public function setUp()
    {
        $this->fizzBuzz = new fizzBuzz();
    }

    public function testResult()
    {
        $this->assertEquals($this->fizzBuzz->judge(3),  "Fizz");
        $this->assertEquals($this->fizzBuzz->judge(9),  "Fizz");
        $this->assertEquals($this->fizzBuzz->judge(10), "Buzz");
        $this->assertEquals($this->fizzBuzz->judge(50), "Buzz");
        $this->assertEquals($this->fizzBuzz->judge(70), "Buzz");
        $this->assertEquals($this->fizzBuzz->judge(90), "FizzBuzz");
        $this->assertEquals($this->fizzBuzz->judge(97), 97);
    }
}
```

このあたりはもっとテストコードの量を書いていくと色々見えてくるのかなと思いますので引き続きトライしてみます。

# 2017/08/03 追記
コメント頂いたことを参考にもう一度FizzBuzz問題にTDDでトライしてみました。
やはりちょっと独学では難しいのかなと思いつつも、PHPUnitについては理解が深まった気がしてます。

```php
<?php

require_once __DIR__. '/fizzBuzz.php';

class testFizzBuzz extends PHPUnit_Framework_TestCase
{
    private $fizzBuzz;

    public function setUp()
    {
        $this->fizzBuzz = new fizzBuzz();
    }

    /**
     * @dataProvider fizzProvider
     */
    public function testFizz($input)
    {
        $this->assertEquals('Fizz', $this->fizzBuzz->testFizzBuzz($input));
    }

    public function fizzProvider()
    {
        return [[3],[9],[33]];
    }

    /**
     * @dataProvider buzzProvider
     */
    public function testBuzz($input)
    {
        $this->assertEquals('Buzz', $this->fizzBuzz->testFizzBuzz($input));
    }

    public function buzzProvider()
    {
        return [[5],[10],[100]];
    }

    /**
     * @dataProvider fizzAndBuzzProvider
     */
    public function testFizzAndBuzz($input)
    {
        $this->assertEquals('FizzBuzz', $this->fizzBuzz->testFizzBuzz($input));
    }

    public function fizzAndBuzzProvider()
    {
        return [[15], [45], [60]];
    }

    /**
     * @dataProvider notFizzBuzzProvider
     */
    public function testNotFizzBuzz($input)
    {
        $this->assertEquals($input, $this->fizzBuzz->testFizzBuzz($input));
    }

    public function notFizzBuzzProvider()
    {
        return [[7], [11], [98]];
    }

}
```

```php
<?php

class fizzBuzz
{
    public function testFizzBuzz($input)
    {
        $res = $input;
        if($input % 3 == 0 && $input % 5 == 0)
        {
            $res = "FizzBuzz";
        }elseif($input % 3 == 0)
        {
            $res = "Fizz";
        }elseif($input % 5 == 0)
        {
            $res = "Buzz";
        }

        return $res;
    }
}
```