单元测试:测试什么/不测试什么?

Ed.*_*Ed. 19 tdd unit-testing

从几天前开始,我开始对C#和VS2010中的单元测试和TDD感兴趣.我已经阅读了博客文章,观看了youtube教程,以及更多解释为什么TDD和单元测试对您的代码如此有用以及如何做到这一点的东西.

但我发现的最大问题是,我不知道在我的测试中要检查什么以及不检查什么.

我理解我应该检查所有逻辑操作,引用和依赖项的问题,但是,例如,我应该为字符串格式创建一个单元测试,这是通过用户输入的吗?或者它只是浪费我的时间,而我可以在实际代码中检查它?

有没有指导澄清这个问题?

Tom*_*icz 18

在TDD中,每行代码必须通过在代码之前编写的失败测试用例来证明.

这意味着没有测试用例就无法开发任何代码.如果你有一行代码(条件,分支,赋值,表达式,常量等),可以修改或删除而不会导致任何测试失败,这意味着这行代码是无用的,删除(或者你有缺少支持其存在的测试).

这有点极端,但这就是TDD的工作原理.话虽这么说如果你有一段代码并且想知道它是否应该被测试,你就没有正确地进行TDD.但是如果你有一个字符串格式化例程或变量增量或任何一小段代码,那么必须有一个支持它的测试用例.

更新(Ed建议的用例):

例如,将一个对象添加到一个列表并创建一个测试以查看它是否真的在里面,或者当列表不允许它们时存在重复.

这是一个反例,您会惊讶地发现复制粘贴错误有多难以及它们有多常见:

private Set<String> inclusions = new HashSet<String>();
private Set<String> exclusions = new HashSet<String>();

public void include(String item) {
    inclusions.add(item);
}

public void exclude(String item) {
    inclusions.add(item);
}
Run Code Online (Sandbox Code Playgroud)

另一方面,测试include()exclude()方法本身就是一种过度杀伤,因为它们本身并不代表任何用例.但是,它们可能是某些业务用例的一部分,您应该进行测试.

显然,你不应该测试是否xx = 7真的是7分配之后.测试生成的getter/setter也是一种过度杀伤力.但它是最容易破解的代码.通常由于复制和粘贴错误或拼写错误(特别是在动态语言中).

也可以看看:


Gar*_*all 14

您的前几个TDD项目可能会导致更糟糕的设计 /重新设计,并且需要更长时间才能完成(至少根据我的经验).这就是为什么你不应该在大型关键项目上使用TDD.

我的建议是在一些小项目(100-10,000 LOC)上使用"纯"TDD(验收/单元测试一切测试优先).您可以自己进行辅助项目,也可以在空闲时间进行编码,在小型内部实用程序中使用TDD来完成工作.

在大约6-12个项目上进行"纯"TDD之后,您将开始了解TDD如何影响设计并学习如何设计可测试性.一旦您知道如何设计可测试性,您将需要减少TDD并最大化单位,回归,验收等测试的ROI,而不是预先测试所有内容.

对我来说,TDD更多的是用于良好代码设计的教学方法,而不是实用的方法.但是,我仍然使用TDD逻辑代码和单元测试代替调试.


zou*_*oul 5

这个问题没有简单的答案.行动中有收益递减规律,因此实现完美覆盖很少值得.知道要测试什么是经验,而不是规则.最好有意识地评估流程.什么东西坏了?测试是否可行?如果没有,是否可以重写代码以使其更易于测试?是否值得在将来测试此类案例?

如果将代码拆分为模型,视图和控制器,您会发现大多数关键代码都在模型中,并且这些代码应该是相当可测试的.(这是MVC的要点之一.)如果一段代码是关键的,我会对它进行测试,即使这意味着我必须重写它以使其更易于测试.如果一段代码容易出错或被未来的更新破坏,它就会得到一个测试.我很少测试控制器和视图,因为它不值得为我带来麻烦.


Ass*_*one 5

在我看来,您的所有代码都属于以下三个类别之一:

  1. 易于测试的代码:这包括您自己的确定性公共方法。
  2. 难以测试的代码:这包括 GUI、非确定性方法、私有方法和具有复杂设置的方法。
  3. 您不想测试的代码:这包括第 3 方代码,以及难以测试且不值得付出努力的代码。

在这三者中,您应该专注于测试简单的代码。在困难的测试代码应该使重构分为两个部分:代码,你不想考易典。当然,您应该测试重构的简单代码。