TDD勉強会レポート

概要

PHPでTDD&CIワークショップ に参加したときのまとめです

講師の方々のお話のまとめ

TDDなんぞ
  • Test Driven Development
参考書

例えば

なんのためのTDDか
  • クリーンなコードを書く
  • レガシーコードをやっつける
  • テストコードを書くことが目的ではない
    • テストコードは副産物
レガシーコード?
  • 「編集して祈る」ことで出来たコード
TDDにおける「テスト」とは?

一般には

などがあるが、TDDの「テスト」は開発促進のためのテスト。

  • 開発者の、開発者による、開発者のためのテスト。
  • 「書いたコードが意図したとおりに動く」という自信を得る。

ワークショップのまとめ

内容

TDDの実践として,FizzBuzzの問題を2人一組でペア・プログラミングするワークショップが行われました.
以下にテストコードの書き方(書く際の方針)として話題に挙がったものをまとめます.

テストコードの書き方
  • 最初にassertから書くことを心がける
    • どうテストするかではなく、何をテストするかを最初に考える。
  • 仮実装はテストコードのテストになる
<?php
class FizzBuzz
{
    function getFizzBuzz( $i )
    {
        // 仮実装
        return "Fizz";
    }
}

class FizzBuzzTest extends PHPUnit_Framework_TestCase
{  
    function testFizzBuzz()
    {
        $obj = new FizzBuzz();
        // 現状の仮実装の場合,下記のassertがFailとして検出されるはずである
        $this->assertEquals( "1", $obj->getFizzBuzz( 1 ) );
    }
}
  • テストメソッドの中はできるだけ1個のassertが実行されるようにする。
    • 1個目がfailになると2個目以降がテストされなくなるため。
  • テストメソッドには良い名前を付けよう
  • テストコードに不安があると意味が無い
  • 例外が正しく投げられる事をテストしたい場合
    • 2つ書き方がある。

a. アノテーションを使う書き方

<?php
class Foo
{
    public void someMethod( $some_integer )
    {
        if( $some_integer < 0 )
        {
            throw new OutOfRangeException();
        }
        // do something
    }
}

class FooTest extends PHPUnit_Framework_TestCase
{
    /**
     * @expectedException OutOfRangeException
     */
    public function testFoo()
    {
        $obj = new Foo();
        // 例外を投げることを期待
        $obj->someMethod( -1 );
    }
}

b. try-catchを使う書き方

<?php
class FooTest extends PHPUnit_Framework_TestCase
{
    public function testFoo()
    {
        try
        {
            $obj = new Foo();
            // 例外を投げることを期待
            $obj->someMethod( -1 );
            $this->fail(); // 例外が正しく投げられないと
                           // ここに到達するため、テストは失敗する。
        }
        catch( OutOfRangeException $e )
        {
            // テスト成功
            return;
        }
        catch( Exception $e )
        {
             // 期待した例外が投げられないため、テストは失敗する。
             $this->fail();
        }
    }
}
    • a.とb.の書き方は一長一短がある。
    • a.の書き方は、ドキュメントとして例外の情報が残るメリットがある反面、どこでFailureが起こったかを取得できない。
    • b.の書き方は、どこでFailureが起こったかを取得できる反面、ドキュメントとして例外の情報が残らない。

感想など

  • TDDを自分の趣味のプログラミングにも導入してみたが,テストコードを書かない場合に比べて安心して実装作業ができるようになった.
  • 一人でコードを書く場合であっても,「テストコードを書く」と「実装する」の2つ立場からコーディングを行うことになるため,自然と「テストコードに漏れが無いかどうか」などと考えながら作業ができるようになった.