22

我目前正在尝试为一个小型库构建一套或多或少完整的单元测试。由于我们希望允许存在不同的实现,我们希望这组测试是 (a) 通用的,以便我们可以重新使用它来测试不同的实现,并且 (b) 尽可能完整。对于(b)部分,我想知道是否有测试枚举类型的最佳实践。例如,我有一个枚举如下:

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

在这里,我想确保所有枚举类型都确实存在。这甚至有必要吗?目前我正在使用 Hamcrests assertThat,如下例所示:

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

缺少“一月”枚举会导致编译时错误,可以通过创建缺少的枚举类型来修复该错误。

我在这里使用 Java,但我不介意您的答案是否适用于其他语言..

编辑:

正如 mkato 和 Mark Heath 都指出的那样,测试枚举可能没有必要,因为当您使用不存在的枚举类型时编译器不会编译。但我仍然想测试这些枚举,因为我们想构建一个单独的类似 TCK 的 test.jar,它将在不同的实现上运行相同的测试。所以我的问题更像是:测试枚举类型的最佳方法是什么?

在考虑了更多之后,我将上面的 Hamcrest 语句更改为:

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

当 1 月(还)不存在时,此语句现在会引发 NPE。这种方法有什么问题吗?

4

5 回答 5

32

对于枚举,我仅在它们实际上包含方法时对其进行测试。如果它是像您的示例一样的纯值枚举,我会说不要打扰。

但是由于您热衷于对其进行测试,因此使用第二种选择比第一种要好得多。第一个问题是,如果您使用 IDE,对枚举的任何重命名也会重命名测试类中的枚举。

于 2009-07-09T13:09:42.957 回答
14

我同意aberrant80

对于枚举,我仅在它们实际上包含方法时对其进行测试。如果它是像您的示例一样的纯值枚举,我会说不要打扰。

但是由于您热衷于对其进行测试,因此使用第二种选择比第一种要好得多。第一个问题是,如果您使用 IDE,对枚举的任何重命名也会重命名测试类中的枚举。

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

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

简单示例

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));
    }
}
于 2011-10-24T21:39:32.180 回答
5

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

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

于 2009-07-03T15:01:27.413 回答
5

您可以测试是否具有某些值,例如:

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

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

于 2013-10-02T03:09:18.487 回答
4

如果您在代码中使用所有月份,您的 IDE 不会让您编译,所以我认为您不需要单元测试。

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

于 2009-07-03T14:55:58.067 回答