我曾计划研究并将单元测试应用到我的代码中,但是在与我的同事交谈之后,他们中的一些人向我暗示这是没有必要的,并且几乎没有好处。他们还声称只有很少的公司实际使用生产软件进行单元测试。
我很好奇人们在工作中如何应用单元测试,以及使用它们会获得什么好处,例如更好的代码质量,减少长期的开发时间等。
我曾计划研究并将单元测试应用到我的代码中,但是在与我的同事交谈之后,他们中的一些人向我暗示这是没有必要的,并且几乎没有好处。他们还声称只有很少的公司实际使用生产软件进行单元测试。
我很好奇人们在工作中如何应用单元测试,以及使用它们会获得什么好处,例如更好的代码质量,减少长期的开发时间等。
Answers:
其中一些建议我没有必要
好吧,从严格意义上讲,它们是正确的:测试,代码审查,源代码控制等也不是必须的。从长远来看,只有极少数明智的开发人员可以在没有这些开发人员的情况下工作。我们大多数人都从错误中了解了(通常是艰难的方式)为什么是最佳做法。
它几乎没有好处。
这是不是在大多数情况下都是这样。就是说,如果我们谈论的是应该在未来几年内使用的生产软件,那么在维护中。
他们还声称只有极少数的公司对生产软件进行单元测试。
这可能是正确的(尽管以我的经验越来越少),但是对于单元测试的价值却无话可说。与此相反,一个古老的笑话“狗屎很好-500亿只蝇没错!” ;-)
您在工作中应用了单元测试,您从中得到什么?(例如,更好的代码质量,减少长期时间等)
十多年来,我一直在可能的情况下在我的工作中应用单元测试。对我的代码充满信心,知道它可以工作-我可以随时随地在几秒钟内一次又一次地证明它,而不是仅仅相信它-是无价的。它使我有勇气重构我的代码,改进其设计或修复错误,而不必担心破坏现有功能。我永远不会回到“编码和祈祷”的过去。
我进行单元测试,但没有(或很少)参加工作
我得到的测试的主要好处是,重构要容易得多,并且可以注意到回归(即重新引入已经修复的错误)。
测试以“构建”为生命:您在运行测试的情况下签出软件,直到所有测试都在您的修改下运行后才签入。
因此,以我的经验,以独狼的方式编写测试几乎没有用。当您总是必须调整测试以适应其他更改时,由于“他们不会让我部署”等原因,您的同事可能会删除测试(发生在我之前的工作中),等等。团队的其他成员立即受益。
当整个团队都同意时(以一个简单的团队为一组),以我的经验来看,测试对于项目的质量,样式和健壮性是很大的好处。
但是,在一个诚实地相信“只有少数几家公司会自动测试其代码”并且确信反正他们在浪费时间的团队中,似乎几乎没有希望获得这些好处的希望,但您很有可能会因此而受益。指出错误时的“时间损失”。
引入测试的最佳机会将是您自己负责的一个小项目。在那里,您将有机会发光并展示测试的价值。
我倾向于支持您的同事,但仅限于此。
单元测试的问题在于,它们经常是在琐碎的情况下写的,而这些例子在粗略的案例中粗略地研究了一下,发现无论如何它都会起作用。例如:
def add(x, y)
x + y
end
伴随一打测试,以确保添加的内容确实适用于任意选择的用例。h ...
单元测试的基本前提是:如果您的代码中没有错误,那是因为您没有进行足够的测试。现在,何时编写适当的单元测试。答案:
假设您正在开发某种fo网络应用程序,让我们仔细研究一下每个应用程序。
您为新功能编写了一些代码,并且现在应该可以正常工作了。然后,您可以通过浏览器进行更深入的测试来验证浏览器是否正常工作,对吗?Bzzzt!...错误的答案。您编写一个单元测试。如果您现在不这样做,那么您可能永远也不会这样做。这是单元测试很好运行的地方之一:测试高级功能。
然后,您会发现一个错误(谁不会错过任何错误?)。这使我们指出了第二点。您将回到代码中并开始执行以下步骤。这样做时,请在关键的断点处编写单元测试,在这些关键点上,保持一致和正确的数据至关重要。
最后一点是相反的。您正在设计一些繁琐的功能,其中涉及大量的元编程。它会迅速生成具有数千种潜在方案的决策树,并且您需要确保它们中的每一个都能正常工作。在编写此类内容时,在这里或那里进行简单的更改可能会在食物链的下游产生难以想象的后果。假设您正在设计使用SQL触发器的MPTT实现-使其可以与多行语句一起使用。
在这种棘手的环境中,您通常会希望高度自动化测试。因此,您可以编写脚本来自动生成测试数据,并对该测试数据进行大量单元测试。执行此操作时不要忘记的关键一件事是,您还需要为单元测试生成器编写单元测试。
底线:单元测试,肯定是的。但是,请避免使用基本功能-直到您真正需要它们进行调试,或者确保某些功能丰富的功能正常工作为止(在后一种情况下,包括测试本身)。
所有代码都必须经过测试。别无选择。
未经测试的代码是无用的:它不能被信任做任何事情。
您可以编写单元测试,也可以希望编写更高级别的集成测试或验收测试。
单元测试更易于编写,调试和管理。
集成测试基于单元实际工作的假设。没有单元测试,您如何知道单元工作?如果您不知道要集成的各个单元是否实际工作,该如何调试集成测试?
同样,验收测试取决于所有工作的零件。如果没有一套单元测试,如何知道零件和零件的工作原理?
测试是强制性的。所有更高级别的测试均取决于实际工作的单元。
这使得单元测试成为必然。别无选择。
我对编写的所有内容均使用单元测试,并且在没有测试用例的情况下,请勿让任何未经测试的代码通过审查。(但是我缺少覆盖率工具,因此我不得不考虑测试覆盖率。一次一件事……)
这很简单:如果您无法证明自己的代码有效(以及比测试形式的可执行文件规范更好的方法?),那么它将无法正常工作。
这给了我:
单元测试是一门学科。因为不需要代码工作,所以通常将其丢弃。
但是,这是一种行之有效的方法,可导致健壮且错误较少的代码。正如您已经提到的,我认为我不需要向您解释好处。如果您查看一些领先的开源项目,无论它们是JavaScript库,全栈框架还是单一用途的应用程序,它们都使用单元测试。
我怀疑建议不要使用它的同事不是程序员。如果是的话,那么我们可以说没有比Martin Fowler或Kent Beck等人更有价值的人了;)。
与大多数最佳做法一样,好处是长期的,您需要花一些时间。您可以编写很长的程序代码脚本,但是我们都知道,当您需要在2年后对其进行重构时,希望以面向对象的方式编写它。
单元测试也是如此。如果您为应用程序中的关键部分编写单元测试,则即使在重构代码之后,也可以确保它始终如期运行。也许您的代码编写得如此出色,以至于您永远都不会遇到回归错误。但是,如果您没有这样做,或者新程序员加入了您的团队,那么您想确保过去的错误不会再次发生。我认为您的老板也会对此感到满意,而不是不得不提交他认为已经在半年前解决的错误报告。
单元测试需要对单元测试友好的语言,对单元测试友好的设计和对单元测试友好的问题。
C ++,多线程设计和GUI将是一场噩梦,问题的覆盖范围将令人震惊。
.NET,可重用的单线程dll程序集,纯计算逻辑将轻而易举。
值得,我不能说真的。
您重构很多吗?您在代码中是否经常看到“笨拙的错误”之类的“笨拙的错误”?
无论您做什么,都不要以“没有单元测试,因此很烂”来批评别人。如果测试对您有所帮助,那就去吧,否则,就好像它们不是灵丹妙药。
我想,但是我不幸的是,几乎所有的公司都只在那些不在乎质量的公司工作,而他们更专注于将垃圾整理起来,这在某种程度上是可以的。我已经提到单元测试,并且得到“呵呵”。外观(当我提到SOLID原理或ORM或“除所有静态方法的类之外”或遵循.NET命名约定以外的设计模式时,会得到相同的外观)。我只去过一家了解这方面知识的公司,但不幸的是这是一份短期合同,该部门已裁员以削减成本,因此没有足够的时间来真正学习。
我曾涉足一次性虚拟项目中的单元测试,但是我并没有真正了解成熟的TDD / BDD,也没有一位导师可以帮助您解决这个问题,因此很难正确地完成它。
我们使用它们。我们获得的一大好处是,我们的单元测试框架可以检查内存泄漏和分配失败。有时问题出在单元测试代码本身中,但通常出在生产代码中。
这是查找代码审查中遗漏的那些东西的好方法。
单元测试(应该)也非常快地运行,并且可以在每次提交后作为持续集成的一部分运行,也可以由开发人员在提交之前进行。我们有1,000多个,运行时间不到20秒。
与之相比,系统级自动化测试需要40分钟以上的时间,而人工测试则需要数小时/天的时间。当然,单元测试不是您应该做的唯一测试,但是在细粒度的代码级别,它们可以帮助发现错误并测试系统/集成测试无法触及的那些极端情况。我们的代码必须以超过75%的决策覆盖率和100%的功能覆盖率进行测试,如果没有单元测试,这将很难实现。
我看到对单元测试进行编码和使单元测试执行成为日常构建过程的一部分的真正优势是在一个项目中,该项目有30多个开发人员在3个不同的大陆工作。单元测试真正闪耀的地方是某人在不了解人们如何使用该类的情况下巧妙地更改了他们所维护的类。当其他人的单元测试由于更改而开始失败时,可以立即得到反馈,而不必等待代码进入测试组。[这就是为什么所有单元测试都需要定期运行的原因,而不仅仅是您为代码编写的测试。]
我的单元测试准则是: