分组测试的单元测试名称约定

Unit Tests name convention for grouping tests

我阅读了一些关于测试命名约定的文章,并决定使用 "should" 中的一篇。在大多数情况下它工作得很好,例如:

但我在测试 DecimalRepresentation class 时遇到问题,它显示不同数字系统的数字,请看代码:

public class DecimalRepresentationTest {

    private DecimalRepresentation decimal;

    @BeforeEach
    void setup() {
        decimal = new DecimalRepresentation();
    }

    @Test
    void shouldReturnZeroIfNumberNotSpecified() {
        assertEquals("0", decimal.toBinary());
    }

    @Test
    void shouldReturn10IfNumber2() {
        decimal.setNumber(2);
        assertEquals("10", decimal.toBinary());
    }

    @Test
    void shouldReturn1111IfNumber15() {
        decimal.setNumber(15);
        assertEquals("1111", decimal.toBinary());
    }
}

现在还不错,但如果我正在测试负输入,它看起来很糟糕:

    @Test
    void shouldReturn11111111111111111111111110001000IfNumberNegative120() {
        decimal.setNumber(-120);
        assertEquals("11111111111111111111111110001000", decimal.toBinary());
    }

    @Test
    void shouldReturn11111111111111111111111111111111IfNumberNegative1() {
        decimal.setNumber(-1);
        assertEquals("11111111111111111111111111111111", decimal.toBinary());
    }

在上面的示例中,我对正输入和负输入进行了两次测试,以确保没有硬编码结果并且算法工作正常,因此我决定将测试分组在嵌套 classes 中以保持约定:

@Nested
@DisplayName("Tests for positive numbers")
class PositiveConverter {
    @Test
    void shouldReturn10IfNumber2() {
        decimal.setNumber(2);
        assertEquals("10", decimal.toBinary());
    }

    @Test
    void shouldReturn1111IfNumber15() {
        decimal.setNumber(15);
        assertEquals("1111", decimal.toBinary());

    }
}

@Nested
@DisplayName("Tests for negative numbers")
class NegativeConverter {
    @Test
    void shouldReturn11111111111111111111111110001000IfNumberNegative120() {
        decimal.setNumber(-120);
        assertEquals("11111111111111111111111110001000", decimal.toBinary());
    }

    @Test
    void shouldReturn11111111111111111111111111111111IfNumberNegative1() {
        decimal.setNumber(-1);
        assertEquals("11111111111111111111111111111111", decimal.toBinary());
    }
}

我意识到由于惯例,它过于复杂了。万一我失误,它看起来会好得多:

@Test
void testPositiveConversions() {
    assertAll(
            () -> {decimal.setNumber(2); assertEquals("10", decimal.toBinary());},
            () -> {decimal.setNumber(15); assertEquals("1111", decimal.toBinary());}
    );
}

@Test
void testNegativeConversions() {
    assertAll(
            () -> {decimal.setNumber(-120); assertEquals("11111111111111111111111110001000", decimal.toBinary());},
            () -> {decimal.setNumber(-1); assertEquals("11111111111111111111111111111111", decimal.toBinary());}
    );
} 

我应该打破常规以保持简单吗?我在测试中遇到的相同命名问题,他们得到带有输入和输出或动态测试的列表:

@TestFactory
Stream<DynamicTest> shouldReturnGoodResultsForPositiveNumbers(){ // look at method name lol
    List<Integer> inputs = new ArrayList<>(Arrays.asList(2, 15));
    List<String> outputs = new ArrayList<>(Arrays.asList("10", "1111"));

    return inputs.stream().map(number -> DynamicTest.dynamicTest("Test positive " + number, () -> {
        int idx = inputs.indexOf(number);
        decimal.setNumber(inputs.get(idx));
        assertEquals(outputs.get(idx), decimal.toBinary());
    }));
}

名字应该会有帮助。有时规则有助于找到好名字,有时则不然。然后答案就是放弃规则,也许会选择完全不同的东西,比如:

@Test
void testResultForNegativeInput() {
  decimal.setNumber(-120);
  assertEquals("11111111111111111111111110001000", decimal.toBinary());
 }

如果您有其中几种方法,也许添加 "ForMinus120" 左右就可以接受 table。

但不要在这里花费精力命名:真正的问题是您使用了错误的测试类型:您有一大堆 input 数据,这只会导致要检查的不同输出值。你所有的测试都是关于:一个特殊的输入值应该导致一个特殊的输出值。

你不会用许多几乎相似的测试方法来做到这一点——而是转向 parameterized tests! Meaning: use a table to drive your test. For JUnit5 and parameterized tests turn here (thanks to user Sam Brannen)。

很高兴您花时间和精力使您的测试易于阅读。但在这种情况下,这会导致大量代码重复。相反,将 input/output 值放入 table,并进行 one 测试以检查该 table.

我已经按照 Roy Osherove's 方法对我的模型进行了建模,这是正则表达式

^(setup|teardown|([A-Z]{1}[0-9a-z]+)+_([A-Z0-9]+[0-9a-z]+)+_([A-Z0-9]+[0-9a-z]+)+)$