分组测试的单元测试名称约定
Unit Tests name convention for grouping tests
我阅读了一些关于测试命名约定的文章,并决定使用 "should" 中的一篇。在大多数情况下它工作得很好,例如:
- shouldAccessDeniedIfWrongPassword
- shouldReturnFizzBuzzIfDiv3And5
- shouldIncreaseAccountWhenDeposit
但我在测试 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]+)+)$
我阅读了一些关于测试命名约定的文章,并决定使用 "should" 中的一篇。在大多数情况下它工作得很好,例如:
- shouldAccessDeniedIfWrongPassword
- shouldReturnFizzBuzzIfDiv3And5
- shouldIncreaseAccountWhenDeposit
但我在测试 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]+)+)$