当要测试的类很复杂时,如何编写单元测试?

时间:2012-05-17 15:12:00

标签: c++ unit-testing tdd code-coverage cxxtest

我正在尝试使用 TDD 在使用VS 2010的C ++中编写步步高游戏。

我已设置CxxTest来编写测试用例。

要测试的第一个课程是

class Position
{
public:
...
...
bool IsSingleMoveValid(.....)
...
...
}

我想为函数 IsSingleMoveValid()编写一个测试,我猜测试应该证明该函数正常工作。不幸的是,有很多情况要测试,即使我测试了几个案例,有些可能会逃脱。

你有什么建议? TDD如何处理这些问题?

5 个答案:

答案 0 :(得分:8)

一些指导原则:

  1. 测试常规案例。在您的问题中:测试您知道的合法移动是否有效。您可以采用简单的方法,只有少数测试用例,或者您可以编写一个循环,生成应用程序中可能发生的所有可能的合法移动并对其进行全部测试。
  2. 测试边界情况。这不是真的适用于您的问题,但是为了测试f(x)形式的简单数字函数,您知道x必须位于范围[x_min, x_max)中,您通常也会测试{ {1}}。 (如果你的内部董事会代表有溢出边缘,它可能与棋盘游戏相关)
  3. 测试已知错误。如果您遇到f(x_min-1), f(x_min), f(x_max-1), f(x_max)无法识别的合法移动,则将其添加为测试用例,然后修复代码。保留这些测试用例以防止将来的回归是有用的(未来的某些代码添加/修改可能会重新引入此错误,并且测试会捕获它)。
  4. 测试覆盖率(测试涵盖的代码行百分比)是可以通过gcov等工具计算的目标您应该自己进行成本效益分析想要测试你的代码。但是对于像游戏程序中的合法移动检测那样重要的东西,我建议你在这里保持警惕。

    其他人已经评论过在较小的子测试中分解测试。其命名是使用单元测试测试此类隔离函数,而使用集成测试测试更高级代码中此类函数之间的合并。

答案 1 :(得分:2)

通常,通过将复杂的类分解为多个更简单的类,每个类都执行易于测试的定义良好的任务。

答案 2 :(得分:2)

如果您正在编写测试,那么最简单的方法就是将IsSingleMoveValid函数分解为更小的函数并单独测试它们。

答案 3 :(得分:1)

正如您在维基百科上看到的那样,TDD - Test Driven Development意味着首先编写测试。

在您的情况下,它意味着建立所有有效的移动并为它们编写测试函数。然后,为每个破坏测试编写代码,直到所有测试都通过。

  

...不幸的是,有很多案例需要测试,即使我测试了几个案例,也有些案例可能会逃脱。

正如其他人所说,当一个函数太复杂时,是重构的时候了!

我强烈建议您使用Martin Fowler的书Refactoring - Improve the Design of Existing Code以及Kent Beck和其他人的贡献。这是一本学习和参考书,在我看来它非常有价值。

这可能是关于重构的最好的书,它将教你如何在不破坏一切的情况下分割你的功能。此外,重构是TDD非常重要的资产。 :)

答案 4 :(得分:0)

没有“太多案例要测试”。如果可以编写处理一组案例的代码,则需要考虑它们。如果它们可以被编写并被思考,那么它们代码可以测试它们我们是否也可以编写。平均而言,对于您编写的每10行(可测试)代码,您可以添加与其关联的测试代码的常量因子。

当然,整个技巧是知道如何编写与 testable 描述相匹配的代码。

因此,您需要首先为所有案例编写测试。

如果有一个大的,让我们说为了讨论你有一组可数的可能案例来测试(即:为所有n和m整数添加(n,m)== n + m),但是你的实际代码非常简单;返回n + m。这当然是真实的,但不要错过这一点:你不需要测试板中所有可能的移动,TDD的目的是让你的测试覆盖所有的代码(即:测试运行所有的if分支)你的代码),不一定是所有可能的值或状态组合(指数大)

具有80-90%线路覆盖率的项目,意味着您的测试在每10行代码中运行9行。一般情况下,如果您的代码中存在错误,则在大多数情况下,在走特定代码路径时都会出现错误。