📝

TDD グリーンバーにするための 3 つの戦略

2024/11/24に公開

はじめに

ソフトウェア開発の設計手法として広く認知されている TDD ですが、きちんと勉強したことがなかったので、TDD の原典とも言えるテスト駆動開発を読みました。
https://books.rakuten.co.jp/rb/14869144/

「テストを先に書くもの」くらいの浅い認識しかなかったので、とても学びになりました。
この記事では、先にテストを書いてレッドバーにしたあと、それをグリーンバーにするための戦略についてシンプルなコードを使って書いてみます。

お題

今回のサンプルでは、正の整数を表現する PositiveInt クラスがすでに実装されており、それに偶数判定をするメソッドを追加するケースを考えてみます。

3 つの戦略

グリーンバーにするためには 3 つの戦略があるとされています。

  • 仮実装: ベタ書きの実装。とりあえずグリーンバーにする。
  • 三角測量: 2 つ以上のテストケースから実装を導き出す。
  • 明白な実装: 仮実装を通さず、頭の中の実装をコードに落とす。

仮実装

テストは PositiveInt のオブジェクトが偶数の時に成功するケースにしました。この時点ではテストは通りません。

class PositiveIntTest {
    @Test
    public void testIsEven() {
        PositiveInt two = new PositiveInt(2);
        assertTrue(two.isEven());
    }
}

仮実装は素早くグリーンバーにするための戦略です。isEven() からは固定で true を返すようにし、テスト結果をグリーンにします。

public class PositiveInt {
    private final int value;

    PositiveInt(final int value) {
        if (value < 0) {
            throw new IllegalArgumentException();
        }
        this.value = value;
    }

    boolean isEven() {
        return true;
    }
}

三角測量

先ほどのテストコードに、もうひとつ以上のテストを書くことでプロダクションコードを導き出します。
以下では PositiveInt のコンストラクタに 1 を渡して生成したオブジェクトが奇数であることを確認するケースを追加しました。これでまたテスト結果がレッドになります。

class PositiveIntTest {
    @Test
    public void testIsEven() {
        PositiveInt two = new PositiveInt(2);
        assertTrue(two.isEven());

        // 追加したテストケース
        PositiveInt one = new PositiveInt(1);
        assertFalse(one.isEven());
    }
}

ここから導き出せる実装をコードにし、テスト結果をグリーンにします。

public class PositiveInt {
    private final int value;

    PositiveInt(final int value) {
        if (value < 0) {
            throw new IllegalArgumentException();
        }
        this.value = value;
    }

    boolean isEven() {
        return (value % 2 == 0);
    }
}

明白な実装

書くべきコードがわかっているときに、仮実装や三角測量をしないで、それを直接コードに落とすことです。今回のサンプルで言うと、仮実装の時のテストコードに対して、三角測量で導き出したプロダクションコードを最初から書くことになるかと思います。繰り返しになってしまいますが、あえてコードをあげるとこうなります。

class PositiveIntTest {
    @Test
    public void testIsEven() {
        PositiveInt two = new PositiveInt(2);
        assertTrue(two.isEven());
    }
}
public class PositiveInt {
    private final int value;

    PositiveInt(final int value) {
        if (value < 0) {
            throw new IllegalArgumentException();
        }
        this.value = value;
    }

    boolean isEven() {
        return (value % 2 == 0);
    }
}

おわりに

仮実装という考えが自分には新鮮でしたー。
そして当然これ以外にも多くのことを学びました。たとえば p. 266 の「不安が退屈に変わるまでテストを書く」というのは、TDD としてのテストををどこまで書くのか?という疑問に対する分かりやすく良い指針だと感じました。
まだ読んだことがない方にぜひおすすめしたい本でした。

Discussion