适当的单元测试技术

Mar*_*unt 5 java tdd junit unit-testing

使用TDD当我发现自己需要测试一个常数(最终)HashMap中包含查找值(请参阅下面的原因将其进行更新CASE)

见下文

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");
}}; 
Run Code Online (Sandbox Code Playgroud)

对于TDD,它强调一次测试一件事,所以我开始调用我的类来验证每个元素的有效性,如下所示.

测试风格1

@Test
public void whenWordIsOneThenReturn1(){
   assertEquals(1, WordToIntegerConverter.toInteger("One"));
}
Run Code Online (Sandbox Code Playgroud)

在编写第三个测试后,我认为它非常荒谬,并使用反向键值对创建了一个临时查找,并开始调用循环进行测试,如下所示.

测试风格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)));
        }
    } 
Run Code Online (Sandbox Code Playgroud)

我的问题是这个; 使用样式1进行单元测试更好还是使用样式2更好.

我看到两者的利弊.例如,样式1非常简洁,只测试一件事并且更容易理解.风格1的缺点除了做大量的打字之外,测试套件将会爆发许多琐碎的测试.风格2的优点是单元测试较少.样式2的缺点有点复杂,并且可能测试不止一件事,但我认为它只测试常量hashmap的有效性.

更新 我收到了这个问题的大量反馈,所以让我进一步解释.它本身并不是我关心的常数,而是验证了我的代码的不同情况.这是一个练习题(练习TDD Via Katas)而不是生产代码.问题是将数字转换为单词,所以我在单元测试中关心的是确保我能够正确处理不同的数字.还有其他常量,我没有包括例如常量存储青少年数字(11,12,13 ......)和tensDigits(20,30,40 ......).在这里打个字很容易.

Nat*_*hes 10

方法#1完成工作,只需要进行大量的切割粘贴.方法#2修复了这一问题,但代价是测试不是独立的:如果一个测试失败,则以下测试不会运行.修复一个测试只是为了找到一堆新的现在失败是非常烦人的.你可以通过参数化测试来改进这个,这是junit的wiki中一个例子:

@RunWith(Parameterized.class)
public class FibonacciTest {
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {     
                 { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }  
           });
    }

    private int fInput;

    private int fExpected;

    public FibonacciTest(int input, int expected) {
        fInput= input;
        fExpected= expected;
    }

    @Test
    public void test() {
        assertEquals(fExpected, Fibonacci.compute(fInput));
    }
}
Run Code Online (Sandbox Code Playgroud)

该参数测试包括输入/​​预期输出对的集合,每对输入和输出得到传递到构造函数调用的测试和测试方法被调用新的测试实例.循环保存在测试框架中并且不在测试之中,并且每个测试独立于其他测试成功或失败.