我的项目需要多大才能进行单元测试?[关闭]


86

我认为我的项目已解耦到足以进行单元测试的程度。但是,就笔迹和功能而言,我的项目到底需要多大才能使单元测试值得?

我们都会犯错,没有人能做到完美,但是我认为自己是一个体面的程序员,可以逐步解决小项目的错误。还是您的项目规模不限,都必须进行单元测试?


26
您所做的一个大不正确的假设是,该项目仅适合您,并且仅目前。如果您将其放置几个月,再做其他事情,然后又回到原来的状态,该怎么办?您对成为“像样的程序员”是否有同样的信心(与是否测试无关)?如果其他人接管您的项目怎么办...?一个伟大的博客作者(很难再活动了)写道,您应该始终“迎合代码读取器,而不是代码编写器”。
阿莫斯·卡彭特

6
怎么样(对于C#.NET意味着):int x = 3 *(1/3); 操作完成后,x中存储的值是多少?我的意思是,甚至一个行代码都可能需要测试,因为它可能会导致错误,或者是因为您不知道,或者因为您知道但做错了代码。
NoChance 2012年

2
@aaamos,我想你错过了我的意思。仅问这个问题的事实表明,我也考虑满足代码读取器的需求。
拉明·桑内

13
两种方法都做到了,我可以告诉您,编写一个正在进行的测试(即,在项目很小的时候)要容易得多,而回去之后再编写单元测试时,您会觉得项目遇到了一些随意的事情要容易得多。我们应该立即编写测试”条件。
桑科旺科(Wonko the Sane),2012年

1
您问错了问题。项目多大无关紧要。问题是,您是否在乎它是否正确?如果正确性很重要,那么单元测试是提高正确性的有效方法。
Mark E. Haase

Answers:


206

您的项目已经足够大了。

以我的经验,一个类和一个功能足以考虑进行单元测试的必要性。

    class Simple {
        boolean reallySimple() {
            return true; // how do we make sure it doesn't change to false?
        }
    }


    class SimpleTest {
        void assertReallySimple() {
            // ensure reallySimple return value isn't changed unexpectedly
            UnitTestFramework.assertTrue(new Simple().reallySimple());
        }
    }

24
当然,您应该早于0 class / 0功能点开始……如果您遵循TDD :)
Kaz Dragon

115
+1。如果您的程序足够大,可以有错误,那么它足够大,可以进行单元测试。
杰森·奥伦多夫

9
@JasonOrendorff:我正在将其模拟成海报,并将其放在我的办公室中。辉煌。
贾斯汀(Justin)2012年

另外,它允许“安全”重构。
2012年

7
尽管我不一定不同意这种观点,但是如果您的代码确实如此简单,那么您可能只需要断言而不是进行全面的单元测试。
Chuu 2012年

109

我从来没有接受过“必须对所有内容进行单元测试”的想法,尽管肯定有一些人(请参阅gnat的答案!)。

就我而言,单元测试的主要好处是:

  1. 帮助确保更改不会破坏事情。
  2. 帮助您设计对类的明智接口(因为它迫使您成为自己代码的客户端)。
  3. 帮助记录如何使用您的代码。

基本上,您需要权衡这些因素所花费的时间来编写和维护测试。

1号通常足以使其值得编写测试。根据我的经验,迟早会有超过95%的代码被修改。


8
同意这一点-在一家开发人员商店工作时,您需要在软件质量和测试所有内容之间取得平衡(这会占用您很多时间)。别忘了,每次进行更改时,您可能都需要修改单元测试以适合
Matt Wilko,2012年

1
您不应该测试所有内容,但是应该测试暴露给外界的任何行为。测试肯定有维护成本,正如肯特·贝克(Kent Beck)在某些SO答案中所说(我认为是SO)-测试足够使您确信您的代码正确。
韦恩·沃纳

10
我还要补充一点,如果您仅进行最少的自动化测试,则单元测试的目标级别是错误的。取而代之的是进行高级集成/烟雾测试,这些测试可以将端对端地通过应用程序推送一些数据集,而不会模拟任何内容。您希望这些测试尽可能多地利用您的代码库,并涵盖所有正常的用例和执行路径。知道您的更改在应用程序中某处发生故障的几率是75%,比知道您破坏SomeClass.OneOfTheHandfulOfTestedFunctions()的几率要大得多。
丹·尼利

3
嗯,我想您错过了一个:“确保代码按预期的方式运行!”
BlueRaja-Danny Pflughoeft 2012年

3
@ BlueRaja-DannyPflughoeft:实际上,更准确地说:“确保代码通过您编写的单元测试!”
vaughandroid 2012年

34

很简单:如果您在运行一次程序后将其丢弃,则无需进行单元测试。

如果您觉得这太过分了,请考虑替代方案的含义。如果某个大小低于该大小而单元测试不付钱,则您必须牢记:“我是否达到了不可思议的大小?我应该开始编写测试了吗?” 现在,众所周知,程序员在预测未来方面很糟糕,并且在判断自己的技能方面也非常糟糕。现在,即使等待一个月,对您而言仍然清晰的代码将变得难以理解。你是绝对的一个项目,积极某些永远不会被再次利用,而你保持周围只是对你可能想查找你是如何解决的东西之前,远程机会再次请求,并会收到变更请求。

因此,很可能会误判测试是否有帮助,并且当您开始需要测试时,您已经不确定100%实际要测试的语义是什么。由于我认为除琐碎的一次性程序外,所有其他程序都可以从单元测试中受益,因此,我认为,对从未进行过测试的测试进行扩展所付出的成本对于扩展未经测试和无法理解的代码的风险可以忽略不计。


22
众所周知,程序员在判断自己的预测未来技能方面
表现不佳

3
@superM我同意你的看法。在我短暂的职业生涯中,我曾经写过的“运行一次然后扔掉”程序全部搁置了,每隔几天运行一次,并且对业务至关重要。我称“临时”又称临时永久效应。。。叹息
Jalayn 2012年

@Jalayn难道不是简单的答案就是,一旦意识到这一点,就应该回去并添加单元测试?
Cornel Masson

@CornelMasson你说的很对,因为测试缺失,通常很难说服经理“还没有完成” :-)
Jalayn 2015年

@Jalayn:太正确了!
Cornel Masson

22

前一段时间,我发现了一篇不错的文章:为什么单元测试可以加快开发速度。它可以帮助您回答问题。

...如果代码库...提供了大量的单元测试该怎么办?一组会说:“如果所有测试成功,我保证代码仍会执行应做的事情”,如果测试失败,它将准确地向您显示某些行为被破坏的地方。太好了,我可以更改代码以添加我想要的内容,而无需徘徊,如果代码仍然可以执行其应做的事情,那么我只需运行...测试即可,并且有信心。作为软件工程师,这是一个伟大的世界。我注意到我可以更快地前进...

我有信仰”。

这可能是单元测试加速企业环境中开发的最重要原因。

我可以相信,如果所有测试通过,一切仍然可以进行。如果测试失败,他们将指出问题的根源。

...您必须具有较高的单元测试覆盖率良好的单元测试。在遵守这些条件的情况下,您会发现自己在添加新功能上所做的努力几乎与应用程序的大小无关,并且从长远来看将加速开发

迈克尔·费瑟斯(Michael Feathers)在他的一本书中介绍了两种处理代码更改的方法:

  • 编辑祈祷
  • 覆盖并修改。

代码库有多大无关紧要。


18

根据Kent Beck在他对Stack Overflow问题的回答中,您的单元测试有多深?,您应该测试容易出错的代码。

如果我通常不会犯某种错误(例如在构造函数中设置错误的变量),则无需进行测试。


4
好点,这意味着OP的问题是错误的;是否进行测试与项目的规模无关。5行代码库可能需要测试,而大型代码库中的1行方法可能不需要测试(尽管该代码库中的其他功能也需要这样做)。
内森·朗

这可能适用于您一个人从事的小型项目,但是对于一个已经完成的项目(您无法控制将来的工作人员)或任何开源的项目,您都需要测试一切。而且您需要立即开始,因为稍后它将“太难以回填所有已经编写的代码”
xaxxon

@xaxxon:肯特实际上是在与曼苏罗联系的相同答案中谈论这一点的,他说:“在为团队编写代码时,我会修改策略以仔细测试我们共同容易出错的代码。”
henko 2013年

不,那仍然是短视。您不知道将来将由谁来处理代码。这是困扰初级开发人员的心态类型。
xaxxon

5

实施单元测试可以节省时间并改善:

  • 错误追踪
  • 重构和/或重写代码
  • 整合测试
  • 回归测试等

必须为程序的相对复杂的部分编写单元测试。

如果确定现在编写单元测试不会节省将来的时间,则可以跳过它。但是,您永远不会知道,就我个人而言,我不认为不编写单元测试而是手动进行所有测试会更便宜(在时间,金钱和神经方面)。


通常是一个很好的答案,所以+1。但是,我认为您的最后一点错过了您仍然想要/需要手动测试单元测试的事实!
vaughandroid 2012年

@Baqueta,也许我听不清楚,但我并不是说说单元测试完全取代了手动测试
superM 2012年

4

通常,可以通过回答以下问题来回答“我应该对此进行单元测试”:“此功能正常工作是否重要,并且知道何时停止工作对我来说很重要?”

当然,这要复杂得多,但这是一个很好的起点。最终,您还将权衡代码是否已经通过在另一个函数中使用而进行了测试,或者您的时间是否会花费在另一个函数上等,等等。


4

除非您要编写未经测试的代码,否则总会招致测试成本。

有单元测试和没有单元测试之间的区别是编写测试的成本和运行测试的成本与手工测试的成本之间的差异。

如果编写单元测试的成本为2分钟,而运行单元测试的成本实际上为0,但是手动测试代码的成本为1分钟,那么在两次运行测试时您将收支平衡。


多年以来,我一直误以为我没有足够的时间为我的代码编写单元测试。当我确实编写测试时,它们是肿的,沉重的东西,这仅鼓励我认为我应该只在知道需要它们时才编写单元测试。

最近,我被鼓励使用“ 测试驱动开发”,我发现它是一个完整的启示。我现在坚信,我没有时间编写单元测试

根据我的经验,通过考虑测试进行开发,最终会得到更简洁的界面,更集中的类和模块以及通常更多的SOLID可测试代码。

每次我使用没有单元测试的旧代码,而不得不手动测试某些东西时,我一直在想:“如果此代码已经具有单元测试,这将更快。” 每当我不得不尝试向具有高耦合性的代码中添加单元测试功能时,我总是在想:“如果以非耦合的方式编写,这将变得更加容易”。


TL; DR版本:

当编写测试的成本加上需要运行多次的成本时,编写测试的成本可能会比手动测试所需的多次成本低。

请记住,尽管使用TDD,但随着测试的提高,编写测试的成本可能会降低,并且除非代码绝对琐碎,否则最终运行测试的频率可能会超出预期。


3

因为你一旦测试观察回归发生或恐惧造成了一些与你的编辑和没有注意到。

Kindle感到恐惧,让它增长到适当的大小:测试越早越好。

请注意:根据您在项目中的角色,单元测试可能不是您要编写的唯一测试类型。

过去,由于主流测试实践不当,每个人都应该沉迷于单元测试。但是,如果您以前从未进行过测试,那么您真的应该将重点放在一般的测试上,仅凭单元测试并不能解决世界上的问题。


1
我明白您的意思,但是还没有对初学者进行基本测试。您还可以详细说明“一般测试”的含义。谢谢。
拉明·桑尼

1
至少还有两种其他类型的测试-集成测试和验收测试。单元测试涵盖一个特定的单元(例如,该类的此功能应该可以使Fizz the Fizz)。您可以模拟/存根该类与之交互的所有其他地方,并向其传递其他数据。进行集成测试时,您将两个(或多个)类组合在一起以确保您的类按照您认为的方式组合在一起。最终,您建立了足够的测试,正在对整个系统进行端到端测试,有时也称为“烟雾测试”。
韦恩·沃纳

也有回归测试兜售法庭。回归测试通常比单元测试大,可能要花一天的时间才能完成,可能意味着需要访问测试数据和特殊的测试环境。实际上,单元测试是更小,更时尚,更易于维护的(旧式)回归测试版本。
ZJR 2012年

1

我认为,决定项目是否应使用测试的不是项目的大小,而是项目的类型。

如果您正在研究概念验证,或者正在以从编码中学习为目标的其他项目中,则不需要进行测试。如果要使用该项目,甚至将其投入生产,则应进行测试。

罗伯特·C·马丁(Robert C. Martin)的“清洁代码”中的一句名言:“如果编写起来很简单,那么测试就很简单”,因此没有理由跳过简短而琐碎的程序的测试。


0

实际上,这与大小无关,它是您要使用的功能(以及它的年龄)。如果我想学习某项技术的工作原理并计划将其扔掉(我们称这是Scrum的峰值),那么我将在不做大量测试的情况下进行编码。如果您打算进一步开发它(即使只是闲逛),则应该围绕代码编写测试。TDD甚至在测试技术之前就已经是一种设计技术。您需要清楚地了解想要执行的代码,然后再确定执行的细节。我也不会建议尝试围绕大量的旧代码编写大量的单元测试。尝试确定那些复杂的部分(具有很高的圈复杂度/意大利面条式的感觉)和那些经常失败的部分(它们通常是相同的)。正如其他人所建议的那样,我会去阅读肯特·贝克(Kent Beck)关于TDD的书,并且一定会读迈克尔·费瑟(Michael Feather)的书。它们没有涉及的太多是围绕代码编写单元测试的政治方面。许多开发人员讨厌不得不更改其代码以使其可测试,并且许多开发人员根本不认为需要测试代码。这是我们必须从事的职业。其他所有工程学科都必须证明(通常是数学上)他们的工作符合规范。我们应该做同样的事情。


-1

在类或功能的限制中绑定项目,然后判断是否适合单元测试可能是错误的。对应用程序进行单元测试有许多好处,但是当您必须维护应用程序或必须在分布式环境中工作时,真正的美就开始了。所以选择来了。即使您的代码进行很小的更改也会造成灾难。
我不仅会建议“单元测试”,而且还会建议检查您的代码覆盖率,以确保单元测试覆盖了最大数量的代码。代码覆盖率的阈值不得小于95%,目标值必须在100%左右。您可以使用工具来跟踪代码覆盖范围并生成报告。
Visual Studio提供覆盖率数据-http://msdn.microsoft.com/zh-cn/library/ms182496(v=vs.80).aspx
也可以使用NCover或dotCover。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.