如何测试枚举类型?

时间:2009-07-03 14:51:37

标签: unit-testing enums hamcrest

我目前正在尝试为一个小型库构建一组或多或少完整的单元测试。由于我们希望允许存在不同的实现,我们希望这组测试是(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。这种方法有什么问题吗?

5 个答案:

答案 0 :(得分:18)

对于枚举,我只在它们实际上有方法时测试它们。如果它是一个纯粹的价值枚举,就像你的例子,我会说不要打扰。

但是既然你热衷于测试它,那么选择第二个选项要好于第一个选项。第一个问题是,如果您使用IDE,那么枚举上的任何重命名也会重命名测试类中的那些。

答案 1 :(得分:9)

我同意aberrant80

  

对于枚举,我只在它们实际上有方法时测试它们。   如果它只是一个纯粹的价值枚举,就像你的例子,我会说不   烦。

     

但是因为你热衷于测试它,所以选择你的第二个选项是   比第一个好得多。第一个问题是,如果你   使用IDE,枚举上的任何重命名也会重命名   你的考试班。

我会通过添加单元测试来扩展它,Enum可能非常有用。如果您在大型代码库中工作,则构建时间开始加载,单元测试可以是验证功能的更快方法(测试仅构建其依赖项)。另一个非常大的优势是其他开发人员无法无意中更改代码的功能(对于非常大的团队而言,这是一个巨大的问题)。

对于所有测试驱动开发,围绕Enums方法的测试可以减少代码库中的错误数量。

简单示例

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));
    }
}

答案 2 :(得分:4)

通常我会说它有点矫枉过正,但偶尔也有理由为枚举编写单元测试。

有时,分配给枚举成员的值必须永远不会更改,否则旧版持久数据的加载将失败。同样,不得删除明显未使用的成员。单元测试可用于防止开发人员在没有意识到影响的情况下进行更改。

答案 3 :(得分:3)

如果您在代码中使用了所有月份,那么您的IDE将无法编译,因此我认为您不需要进行单元测试。

但是如果你使用反射,即使你删除一个月,它也会编译,所以进行单元测试是有效的。

答案 4 :(得分:3)

你可以测试一下是否有一些值,例如:

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);
}

如果有人删除或添加了某个值,则某些测试会失败。