不変テスト

2006年1月5日

契約によるデザイン(DbC)の支持者とテスト駆動開発(TDD)の支持者の間で、派手ではないものの長い論争があります。今はそれに関して詳しく踏み込みませんが、ダニエル・ジャクソンと話すときに思いついた、2つをまとめるアイデアを紹介します。

DbCでは、各クラスに対して不変性を定義します。この不変性は、常に真である必要があるクラスのプロパティを宣言します。オブジェクトは常に(何かの最中でない限り)不変性を満たす必要があります。Eiffelを使用して、クラス不変性はメソッドの呼び出し前(事前条件のチェック時)と後(事後条件のチェック時)に自動的にチェックされます。不変性における不具合が発生すると、例外がスローされます(パフォーマンス上の理由から、必要に応じてこのチェックを使用しなくすることもできます)。

このアイデアをTDDに適用すると、不変性をテストするための共通メソッドを、本番用クラスで定義し、テストコードでテストすることになります。

よくある些細な事例を紹介しましょう。

public class Bowler ...
    int overs, runs, wickets;

ボーラーの単純な不変性は、これらすべての値が非負であるべきというものです。したがって、次のように不変性を定義できます。

    public boolean passesInvariant() {
        return (runs >= 0 && overs >= 0 && wickets >= 0);
    }

テスト中に初期化とテストの実行のフェーズの後、使ってください。

    public void testConcedingRunsAddsToRunsScore() {
        Bowler botham = new Bowler();       // setup - showing my age
        assert botham.passesInvariant();
        botham.concedeRuns(4);              //exercise
        assert botham.passesInvariant();
        assertEquals(4, botham.getRuns());  //verify
    }

私は自分で試したことはありませんし、それをやった人がいるということも知りません。しかし、興味深い考えとして皆さんにお伝えすることにしました。