何时停止在 TDD 中进行测试
When to stop making tests in TDD
我使用 TDD 开发俄罗斯方块游戏。现在我正在测试 Field class.
的 isEmpty() 方法
我已经写了三个测试用例:
@Test
public void shouldIsEmptyMethodReturnTrueForEmptyField() {
Field field = Field.createStandartEmptyField();
assertTrue(field.isEmpty());
}
@Test
public void shouldIsEmptyMethodReturnFalseIfCellInLowerLeftCornerIsFilled() {
Field field = Field.createStandartEmptyField();
field.fillCellAt(0, 0);
assertFalse(field.isEmpty());
}
@Test
public void shouldIsEmptyMethodReturnFalseIfCellInLowerRightCornerIsFilled() {
Field field = Field.createStandartEmptyField();
field.fillCellAt(field.getWidth() - 1, 0);
assertFalse(field.isEmpty());
}
我的 isEmpty() 方法如下所示
public boolean isEmpty() {
if (isFilledCellAt(0, 0)) {
return false;
}
if (isFilledCellAt(getWidth() - 1, 0)) {
return false;
}
return true;
}
所以我可以进一步编写新的测试用例来测试俄罗斯方块字段中填充单元格的每个组合。 我什么时候必须停下来?使用 TDD 测试俄罗斯方块字段 class 的 isEmpty() 方法的正确方法是什么?
我认为这在很大程度上取决于经验,并没有简单的方法来确定您的答案。编写测试时我会查看:
- 报道。我是否涵盖了 所有 代码路径?或者至少那些我认为可能是问题的潜在原因
- 输入和输出。我是否涵盖了 所有 输入和输出的可能组合。在某些情况下,这是不切实际的(例如,如果您的方法需要一个整数与另一个整数相加,您是否传入 1,2,3....)
- 边缘情况。我的代码是否正确处理 边界 条件?
因此,当我编写代码时,我对需要断言的问题场景有一种感觉,以及我编写的每一行代码是否都以某种方式涵盖。如果我有相当多的 input/output 场景要覆盖,我会考虑实施 table 的 inputs/outputs 来断言并让测试框架总共执行每个场景(例如 Groovy的Spock makes this very easy. Junit's Parameterized Tests是这个的另一个实现)
这主要是个人偏好。但是,如果您想遵循严格的 TDD,那么一旦您无法再编写损坏的测试,您就会想要停止。您首先编写一个失败的测试,然后编写足够的代码来通过该测试。然后你编写下一个失败的测试并继续更新你的代码并重构直到一切都变绿。如果您不能再编写失败的测试,那么您就不需要再编写测试了。
Equivalence partitioning 可以帮助您减少要编写的测试用例的数量。在这里,您可以有 3 个案例:[NoCells, OneCell, ManyCells].
Boundary Value Analysis 是一种补充方法,尽管它更适用于采用自由输入的方法。在这里,上下文实际上不允许低于或超出极端边缘(-1 个单元格或大于一行中的单元格数)。
如果您真的想测试案例组合,Property-based Testing 或其他自动测试数据生成方法可能就是您要找的。
我使用 TDD 开发俄罗斯方块游戏。现在我正在测试 Field class.
的 isEmpty() 方法我已经写了三个测试用例:
@Test
public void shouldIsEmptyMethodReturnTrueForEmptyField() {
Field field = Field.createStandartEmptyField();
assertTrue(field.isEmpty());
}
@Test
public void shouldIsEmptyMethodReturnFalseIfCellInLowerLeftCornerIsFilled() {
Field field = Field.createStandartEmptyField();
field.fillCellAt(0, 0);
assertFalse(field.isEmpty());
}
@Test
public void shouldIsEmptyMethodReturnFalseIfCellInLowerRightCornerIsFilled() {
Field field = Field.createStandartEmptyField();
field.fillCellAt(field.getWidth() - 1, 0);
assertFalse(field.isEmpty());
}
我的 isEmpty() 方法如下所示
public boolean isEmpty() {
if (isFilledCellAt(0, 0)) {
return false;
}
if (isFilledCellAt(getWidth() - 1, 0)) {
return false;
}
return true;
}
所以我可以进一步编写新的测试用例来测试俄罗斯方块字段中填充单元格的每个组合。 我什么时候必须停下来?使用 TDD 测试俄罗斯方块字段 class 的 isEmpty() 方法的正确方法是什么?
我认为这在很大程度上取决于经验,并没有简单的方法来确定您的答案。编写测试时我会查看:
- 报道。我是否涵盖了 所有 代码路径?或者至少那些我认为可能是问题的潜在原因
- 输入和输出。我是否涵盖了 所有 输入和输出的可能组合。在某些情况下,这是不切实际的(例如,如果您的方法需要一个整数与另一个整数相加,您是否传入 1,2,3....)
- 边缘情况。我的代码是否正确处理 边界 条件?
因此,当我编写代码时,我对需要断言的问题场景有一种感觉,以及我编写的每一行代码是否都以某种方式涵盖。如果我有相当多的 input/output 场景要覆盖,我会考虑实施 table 的 inputs/outputs 来断言并让测试框架总共执行每个场景(例如 Groovy的Spock makes this very easy. Junit's Parameterized Tests是这个的另一个实现)
这主要是个人偏好。但是,如果您想遵循严格的 TDD,那么一旦您无法再编写损坏的测试,您就会想要停止。您首先编写一个失败的测试,然后编写足够的代码来通过该测试。然后你编写下一个失败的测试并继续更新你的代码并重构直到一切都变绿。如果您不能再编写失败的测试,那么您就不需要再编写测试了。
Equivalence partitioning 可以帮助您减少要编写的测试用例的数量。在这里,您可以有 3 个案例:[NoCells, OneCell, ManyCells].
Boundary Value Analysis 是一种补充方法,尽管它更适用于采用自由输入的方法。在这里,上下文实际上不允许低于或超出极端边缘(-1 个单元格或大于一行中的单元格数)。
如果您真的想测试案例组合,Property-based Testing 或其他自动测试数据生成方法可能就是您要找的。