web-dev-qa-db-ja.com

列挙型をテストする方法は?

私は現在、小規模なライブラリー用の多かれ少なかれ完全な単体テストのセットを構築しようとしています。異なる実装が存在できるようにしたいので、このテストのセットを(a)汎用にし、それを再利用して異なる実装をテストし、(b)可能な限り完全にする必要があります。 (b)の部分については、列挙型をテストするためのベストプラクティスがあるかどうかを知りたいと思います。たとえば、次のような列挙型があります。

public enum Month {
    January,
    February,
    ...
    December;
}

ここでは、すべての列挙型が実際に存在することを確認します。それも必要ですか?現在、私は次の例のようにHamcrests assertThatを使用しています。

assertThat(Month.January, is(notNullValue()));

「January」列挙型が欠落していると、コンパイル時エラーが発生し、欠落している列挙型を作成することで修正できます。

ここではJava=を使用していますが、あなたの答えが別の言語用かどうかは気にしません。

編集:

MkatoとMark Heathの両方が指摘したように、列挙型を使用していないとコンパイラーがコンパイルできないため、列挙型のテストは必要ない場合があります。しかし、別の実装で同じテストを実行する別のTCKのようなtest.jarを構築したいので、これらの列挙型をテストしたいと思います。だから私の質問は、「列挙型をテストする最良の方法は何ですか?」

それについてもう少し考えた後、私は上のHamcrestステートメントを次のように変更しました。

assertThat(Month.valueOf("January"), is(notNullValue()));

このステートメントは、1月が(まだ)ない場合にNPEをスローします。このアプローチに問題はありますか?

17
seb

列挙型の場合は、実際にメソッドが含まれている場合のみテストします。それがあなたの例のような純粋な値のみの列挙型である場合、私は気にしないでください。

しかし、あなたはそれをテストすることに熱心なので、2番目のオプションを使うことは最初のものよりはるかに優れています。最初の問題は、IDEを使用する場合、列挙型の名前を変更すると、テストクラス内の名前も変更されることです。

21
aberrant80

aberrant8 に同意します。

列挙型の場合は、実際にメソッドが含まれている場合のみテストします。それがあなたの例のような純粋な値のみの列挙型である場合、私は気にしないでください。

しかし、あなたはそれをテストすることに熱心なので、2番目のオプションを使うことは最初のものよりはるかに優れています。最初の問題は、IDEを使用する場合、列挙型の名前を変更すると、テストクラス内の名前も変更されることです。

Enumの単体テストは非常に便利であると追加して、さらに拡張します。大規模なコードベースで作業する場合、ビルド時間が開始し始め、ユニットテストは機能を検証するためのより高速な方法になります(テストは依存関係のみをビルドします)。もう1つの本当に大きな利点は、他の開発者が意図せずにコードの機能を変更できないことです(非常に大規模なチームでは大きな問題です)。

また、すべてのテスト駆動開発では、列挙型メソッドを中心としたテストにより、コードベースのバグの数を減らします。

簡単な例

public enum Multiplier {
    DOUBLE(2.0),
    TRIPLE(3.0);

    private final double multiplier;

    Multiplier(double multiplier) {
        this.multiplier = multiplier;
    }

    Double applyMultiplier(Double value) {
        return multiplier * value;
    }

}

public class MultiplierTest {

    @Test
    public void should() {
        assertThat(Multiplier.DOUBLE.applyMultiplier(1.0), is(2.0));
        assertThat(Multiplier.TRIPLE.applyMultiplier(1.0), is(3.0));
    }
}
9
Mike Rylander

あなたは例によって正確にいくつかの値があるかどうかをテストすることができます:

for(MyBoolean b : MyBoolean.values()) {
    switch(b) {
    case TRUE:
        break;
    case FALSE:
        break;
    default:
        throw new IllegalArgumentException(b.toString());
}

for(String s : new String[]{"TRUE", "FALSE" }) {
    MyBoolean.valueOf(s);
}

誰かが値を削除または追加すると、一部のテストが失敗します。

4
razzek

通常、それはやり過ぎだと思いますが、列挙型の単体テストを作成する理由が時々あります。

列挙型メンバーに割り当てられた値は決して変更してはなりません。そうしないと、レガシー永続データのロードが失敗します。同様に、明らかに未使用のメンバーは削除してはなりません。単体テストは、開発者が影響を認識せずに変更を加えるのを防ぐために使用できます。

4
Mark Heath

コードですべての月を使用する場合、IDEではコンパイルできません。そのため、単体テストは必要ないと思います。

ただし、リフレクションで使用している場合は、1か月削除してもコンパイルされるため、単体テストを実施することは有効です。

3
mkato