【发布时间】:2016-01-13 01:11:09
【问题描述】:
在使用 TDD 时,我发现自己需要测试一个包含查找值的常量(最终)哈希图(请查看原因,为什么这是在 UPDATE 下的情况)
见下文
private static final Map<Integer,String> singleDigitLookup = new HashMap<Integer, String>(){{
put(0,"Zero");put(1,"One");put(2,"Two");put(3,"Three");put(4,"Four");put(5,"Five");put(6,"Six");put(7,"Seven");
put(8,"Eight");put(9,"Nine");
}};
TDD 强调一次测试一件事,所以我开始调用我的班级来验证每个元素的有效性,如下所示。
测试方式 1
@Test
public void whenWordIsOneThenReturn1(){
assertEquals(1, WordToIntegerConverter.toInteger("One"));
}
在写完第三个测试后,我觉得这很荒谬,并使用反向键值对创建了一个临时查找,并开始在循环中调用以进行如下测试。
测试方式 2
@Test
public void whenWordIsZeroThroughNineReturnIntegerConversion(){
HashMap<Integer, String> lookup = new HashMap<Integer, String>(){{
put(0,"Zero");put(1,"One");put(2,"Two");put(3,"Three");put(4,"Four");put(5,"Five");
put(6,"Six");put(7,"Seven");put(8,"Eight");put(9,"Nine");
}};
for(int i = 0; i < 10; i++) {
assertEquals(i, WordToIntegerConverter.toInteger(lookup.get(i)));
}
}
我的问题是这样的;使用样式 1 进行单元测试更好还是使用样式 2 更好。
我看到两者的优点和缺点。比如style 1非常简洁,只测试一件事,更容易理解。样式 1 的缺点除了大量键入测试套件外,还会因许多琐碎的测试而崩溃。样式 2 的优点是更少的单元测试。样式 2 的缺点有点复杂,可能测试不止一件事,但我认为它只测试一件事,即常量哈希图的有效性。
更新 我从这个问题中得到了相当多的反馈,所以让我进一步解释一下。它本身不是我关心的常数,而是验证我的代码的不同情况。这是一个练习问题(通过 Katas 练习 TDD)而不是生产代码。问题是将数字转换为单词,所以我在单元测试中关心的是确保我能够正确处理不同的可能数字。还有其他一些我没有包括的常量,例如常量存储青少年数字(11、12、13...)和 tensDigits(20、30、40...)。这里很容易打错字。
【问题讨论】:
-
在我看来,风格 2(或风格 1)没有任何问题。我有很多使用循环来做出各种断言的测试。只要我涵盖了所有代码,我就很高兴。
-
似乎您可以将查找重构为
enum类型,而不是使用Map。当您有了枚举时,您可能甚至不需要对常量进行单元测试,因为编译器会为您进行类型检查。 -
无需测试,只需目测即可:)
-
所以现在人们正在测试常量...下一步是什么?测试自动生成的 setter/getter 会很快成为一种好习惯吗? (因为测试覆盖率,你知道的)。程序员在“测试”中检查他是否编写了自己编写的代码,这是多么美好的时光。
标签: java unit-testing junit tdd