在方法中单元测试一个相当复杂的条件的最佳实践是什么?

时间:2012-03-14 00:28:54

标签: unit-testing

我有这个方法,从公共设置器调用:

private void EmitEvents(IGridCell[] oldGridCells)
{
    bool wasAllInOneGridCell = _isAllInOneGridCell;

    _isAllInOneGridCell = GridCells[0] == GridCells[1] &&
                          GridCells[2] == GridCells[3] &&
                          GridCells[0] == GridCells[2];

    // All points were in the same grid cell before, and still are
    if (_isAllInOneGridCell && wasAllInOneGridCell && oldGridCells[0] == GridCells[0])
    {
        return;
    }

    for (int i = 0; i < 4; i++)
    {
        GridCellExited(this, new GridCellChangeEventArgs(oldGridCells[i]));
    }

    for (int i = 0; i < 4; i++)
    {
        GridCellEntered(this, new GridCellChangeEventArgs(GridCells[i]));
    }
}

这段代码究竟做了什么并不太重要。我已经对这两项赛事进行了测试。我想知道的是,在测试半复杂条件时,一般应该采用什么方法,例如此方法中的if语句。

由于有3个布尔比较,因此总共有8种不同的组合。当然,我不想写8个单元测试来涵盖所有这些可能性。但那我该怎么办?我想至少检查一下正面条件和一个负面条件,但是不是单元测试工作的一部分,创建了一个类必须坚持的“规范”?

假设我在单元测试中选择的否定案例是_isAllInOneGridCell等于假的案例。然后,假设某人正在进行一些重构,并意外地从&& wasAllInOneGridCell语句中删除了if条件。他们引入了一个错误,但由于我没有编写测试来覆盖这个完全平凡的案例,因此不会导致测试失败。

总而言之,我一方面将单元测试视为定义代码必须遵循的合同的一种方式,以防止回归。不幸的是,为了坚持这一点,我必须做一些疯狂的事情,例如对于一行if声明的正确的8单元测试。这里最好的路线是什么?

2 个答案:

答案 0 :(得分:1)

如果有8种可能的输入输出方案(由您的条件决定)那么您可以做的事情并不多。你要么全部测试,要么不测试。这就像单元测试一样,就像你提到的那样 - 确保合同并防止回归。

但是,如果您发现很难对您的课程进行测试,则可能是一些重构可能有所帮助的迹象。将复杂逻辑移动到单独的类(方法)首先要考虑到。您仍然可能需要对逻辑进行多次测试,但这样做会将其与EmitEvents方法解耦,最终只能在两个条件下验证实际事件验证(逻辑传递 - 提升;逻辑失败 - 不要)。

在这些情况下,这总是一种判断力。你的逻辑是否足够复杂,可以将它分开,还是它仍然是它的一部分?无论如何,如果你想完全测试你的合同,我恐怕没有简短的方法可以做到这一点。

答案 1 :(得分:1)

我认为将许多测试用例集中到一个测试是否公平,如果可以使它更容易。 只要你没有给测试添加很多复杂性,并且在测试本身中引入了错误的风险: - )

在某些情况下,在循环等中生成输入组合以涵盖所有组合是有意义的,而不是手动编码所有内容...... 我同意,虽然决定需要哪些案例,但始终是判决。