TDD与单元测试[关闭]


117

我的公司对单元测试我们的代码还很陌生。我已经阅读了一段时间的TDD和单元测试,并深信它们的价值。我试图说服我们的团队,TDD值得学习和改变关于编程方式的思维方式,但这是一个挣扎。这使我想到了我的问题。

TDD社区中有很多人对编写测试然后编写代码非常虔诚(我和他们在一起),但是对于一个在TDD中苦苦挣扎的团队来说,妥协仍然带来更多的好处吗?

一旦编写了代码(也许是检入代码的要求),我也许可以成功地使团队编写单元测试,并且我的假设是编写这些单元测试仍然有价值。

使陷入困境的团队加入TDD的最佳方法是什么?失败的是,即使在编写代码之后,仍然值得编写单元测试吗?

编辑

我摆脱的是,对于我们而言,在编码过程中的某个位置开始单元测试非常重要。对于团队中支持此概念的人员,应开始朝着TDD进行更多测试并首先进行测试。感谢大家的投入。

跟进

我们最近开始了一个新的小型项目,并且团队的一小部分使用了TDD,其余的在代码之后编写了单元测试。在结束了项目的编码部分之后,那些编写了代码之后的单元测试的人惊讶地发现TDD编码器已经完成并且具有更可靠的代码。这是赢得怀疑者的好方法。我们仍然有很多成长的烦恼,但是意志之战似乎已经结束。感谢所有提供建议的人!


1
您可能会发现此线程有帮助:stackoverflow.com/questions/917334/should-i-use-tdd
Randolpho

29
+1跟随。真是个好故事。
卡尔·曼纳斯特

Answers:


76

如果团队在实施TDD时陷入困境,但是他们之前没有创建任何单元测试,那么……在编写代码之后通过创建单元测试开始它们。即使是在代码之后编写的单元测试也比根本没有单元测试要好!

一旦他们精通单元测试(及其附带的所有内容),您就可以让他们首先创建测试,然后再编写代码。


3
没错,团队之前没有创建任何单元测试。这感觉就像是完整TDD的不错的垫脚石。
Walter

我不能再同意这一点。实际上,我想我几个月前针对类似问题写了类似的文章。在哪...啊!stackoverflow.com/questions/917334/should-i-use-tdd/…–
Randolpho

27

编写代码后,仍然绝对值得编写单元测试。只是有时候有时会更难,因为您的代码并非设计为可测试的,并且您可能过于复杂了。

我认为,将团队纳入TDD的一种实用的好方法是在过渡时期或长期内提供“开发过程中的测试”的替代方法。应该鼓励他们使用他们认为很自然的TDD代码段。但是,在似乎很难先进行测试的部分代码中,或者在使用非敏捷A&D流程预先确定的对象时,可以为开发人员提供编写一小部分代码,然后编写测试以覆盖该部分的选项。代码,然后重复此过程。编写代码后立即编写某些代码的单元测试比根本不编写任何单元测试要好。


16

以我的拙见,用100%的测试覆盖率和50%的使用TDD完成的库比使用“先编码后测试”和100%完成的库具有50%的测试覆盖率更好。不久之后,您的其他开发人员会希望为public他们编写的所有代码编写测试既有趣又具有教育意义,因此TDD会潜入其开发例程中。


3
我不知所措,但是我对50%的测试覆盖率的“ 100%完成的库”感到谨慎……仅从我的经验来看,某些测试未覆盖的每一段代码都至少包含一个错误。或换一种说法:人们倾向于避免为将真正受益于更多测试的代码编写测试:)
Aaron Digulla 09年

2
好吧,另一种表达方式是已发布的错误代码比永远困扰的完美代码要好。显然,也有例外咳嗽 NASA 咳嗽,但在大多数情况下,让你的代码在那里。发行后,您仍然可以添加测试。
jcdyer

3
“ 100%完成的库”是什么意思。您认为它有缺陷是否完整?您是否在完成的定义中包括测试?
Pascal Thivent 09年

10
被测试还不足以确保没有错误
fa。

2
用测试覆盖率工具衡量的测试覆盖率是一把双刃剑。如果通过调用IUT上的所有方法来实现此目的,但是测试并没有真正测试可能会破坏的行为,则开发人员和其他利益相关者将具有错误的安全感。当关键行为未经测试时,您组织内向TDD迈进的整个过程可能会突然爆发,但是您拥有100%的测试覆盖率。最重要的不是数量,而是质量。
Doug Knesek

12

我只是在日历上读到:“每条规则,如果执行得最大,就会变得荒谬甚至危险。” 因此,我的建议是不要对此持虔诚态度。团队中的每个成员都必须在测试的“正确”之间找到平衡。这样,您团队中的每个成员都将最有生产力(而不是说“为什么我必须编写此sti ****测试?”)。

因此,有些测试总比没有好,代码之后的测试要比少数测试好,而代码之前的测试要比之后好。但是每一步都有其优点,您甚至不应该小步走。


“他们的感受”作为开发人员,我不记得曾有过(正确的)渴望通过我自己的感受来进行任何自动化的单元测试,只有手动的感觉。我不认为我一个人缺乏从测试中
走出

@ vgv8:这意味着您的测试无济于事。这可能有很多原因。我建议深入研究。任何项目都将从良好的测试中受益,而遭受不良的测试。当您开始编写良好的测试时,您会注意到,从那时起,没有什么能阻止您编写更多的测试。
亚伦·迪古拉

在我看来,合适的测试级别涵盖了编程单元应该执行的操作,以及从功能级别上进行的测试:用户正常进行的操作,其中包括不良结果,有人将其称为“报告的错误”。如果确认错误,则至少要编写一个测试!项目越大,团队越大,这一点就越重要。
DaFi4 '16

12

TDD是关于设计的!因此,如果使用它,您将确保对代码进行可测试的设计,从而更轻松地编写测试。如果您在编写代码后编写测试仍然很有价值,但是恕我直言,您可能会浪费时间,因为您可能没有可测试的设计。

我可以建议您说服您的团队采用TDD的方法是,使用Mary Lynn Manns和Linda Rising所著的《无畏变革:引入新思想的模式》中描述的一些技术。


3
+1:测试驱动开发意味着设计受测试考虑驱动。
S.Lott

+1。稍后的单元测试当然会为您提供帮助,但如果您不提前编写单元测试,就会失去“可测试设计”的好处。
Noufal Ibrahim 2010年

9

如果不是IMO的测试新手,请从已经编写的测试代码开始,然后慢慢地逐步着手编写测试。作为尝试学习TDD和单元测试新手的人,我发现很难完成一门完整的180测试并改变我的思维方式以在代码之前编写测试,因此我采用的方法大约是50-50 ; 当我确切知道代码的外观时,我将编写代码,然后编写测试以对其进行验证。对于不确定的情况,我将从测试开始,然后逐步进行。

还请记住,编写测试来验证代码没有什么错,而不是编写满足测试要求的代码。如果您的团队不想走TDD路线,请不要强行将其应用在他们身上。


6

一旦编写了代码(也许是检入代码的要求),我也许可以成功地使团队编写单元测试,并且我的假设是编写这些单元测试仍然有价值。

毫无疑问,经过单元测试的代码具有价值(无论编写测试的时间如何),并且我在“完成的定义”中包括了“经过单元测试的代码”。人们只要测试就可以使用或不使用TDD。

关于版本控制,我喜欢将“ 开发分支 ”与单元测试策略一起使用(即代码编译和构建,所有单元测试都通过了)。完成功能后,它们将从开发分支发布到主干。换句话说,主干分支是“ 完成的分支 ”(主干上没有垃圾!),并且具有可 装运策略(可以随时释放),该策略更加严格,并且包含的​​内容比“经过测试的单元”还要多。


4

这是您的团队在开始相信它之前必须取得自己成功的东西。对于那些关心的人,我会为我的nUnit顿悟大声疾呼:

大约5年前,我在从事项目工作时发现了nUnit。我们几乎已经完成了V1.0,我创建了一些测试只是为了尝试这个新工具。我们有很多错误(很明显!),因为我们是一个新团队,任务紧迫,期望很高(听起来很熟悉?),等等。无论如何,我们获得了1.0,并从1.1开始。我们对团队进行了一些重组,我分配了2个开发人员。我为他们做了一个1小时的演示,并告诉他们我们编写的所有内容都必须带有测试用例。在1.1开发周期中,我们不断地落后于团队的其他成员,因为我们正在编写更多的代码,进行单元测试。我们最终付出了更多的努力,但这才是回报-当我们最终进行测试时,我们的代码中有0个错误。我们帮助其他所有人调试和修复了他们的错误。在验尸中,当出现错误计数时,

我还不够愚蠢,以为您可以测试自己的成功之路,但是对于单元测试,我是一个真正的信徒。该项目采用了nUnit,并由于1个成功而很快传播到了所有.Net项目的公司。我们的V1.1版本的总时间为9个开发周,因此绝对不是一朝一夕的成功。但是从长期来看,它对我们的项目和为其构建解决方案的公司都证明是成功的。


“该项目采用了nUnit,并很快将其传播到公司的所有.Net项目中。”如果一个产品/项目具有C#,Java,C ++,SQL Server代码怎么办?
纳季·瓦宁

我不知道...找到一种在部署到生产之前测试所有组件的方法吗?单元测试只是全面测试计划上线之前的一个方面。您可以在任何情况下戳孔。
不退款

4

毫无疑问,测试(第一次,一段时间或什至之后)将节省您的培根,并提高生产率和信心。我建议采用它!

我处于类似的情况,因为我是一个“菜鸟”开发人员,所以在团队项目中工作时,我常常因贡献破坏了构建而感到沮丧。我不知道该责怪我,还是在某些情况下应该责怪谁。但是,我更担心自己对其他开发人员所做的相同的事情。然后,这种认识促使采用了一些TDD策略。我们的团队起初有一些愚蠢的游戏和规则,例如,您必须等所有测试通过后才能回家,或者如果您未通过测试就提交内容,那么您就必须购买所有人“啤酒/午餐/等”,这使TDD变得更加有趣。


3

单元测试最有用的方面之一是确保已经工作的代码的连续正确性。当您可以随意重构时,让IDE提醒您编译时错误,然后单击一个按钮让您的测试发现任何潜在的运行时错误-有时到达以前很简单的代码块,那么我认为您会找到您的团队开始欣赏TDD。因此,从测试现有代码开始绝对是有用的。

另外,直言不讳,我比尝试从TDD开始学习了更多有关如何通过尝试测试已编写的代码来编写可测试代码的知识。如果您试图考虑既可以实现最终目标又可以进行测试的合同,那么起初可能过于抽象。但是,当您查看代码并说“这里的单例完全破坏了依赖项注入并使测试变得不可能”时,您开始对哪种模式使您的测试工作变得更容易了然。


3

好吧,如果您不首先编写测试,那不是“测试驱动”,而是测试。它本身具有好处,如果您已经有了添加测试的代码库,那么即使它不是TDD而是仅仅是测试,它肯定也很有用。

编写测试首先要关注在编写代码之前应该做什么。是的,您还可以进行测试,这很好,但是有些人可能认为这不是最重要的一点。

我要做的就是使用TDD 对团队进行此类玩具项目的培训(请参阅Katas的Coding Dojo)(如果您可以让经验丰富的TDD程序员参加这样的研讨会,那就更好了)。当他们看到好处时,将在实际项目中使用TDD。但是与此同时,不要强迫他们,因为他们看不到不会做对的好处。


3

如果您在编写代码之前进行了设计会议,或者必须生成设计文档,则可以将单元测试添加为会议的有形成果。

然后,这可以作为有关代码应如何工作的规范。鼓励在设计会议上进行配对,以使人们谈论在给定场景下某件事情应该如何工作以及应该做什么。什么是边缘情况,为它们提供显式测试用例,以便每个人都知道,例如,如果给定null参数,它将要做什么。

暂且不提,但BDD也可能引起您的兴趣


我没有意识到BDD。我将不得不阅读更多有关它的内容。
Walter

3

通过显示一个或两个示例,TDD会减少编写代码的次数,您可能会发现一些吸引力-因为您只编写测试通过所需的代码,所以抵制金牌或参与YAGNI的诱惑更容易抵制。您不需要编写的代码不需要维护,重构等,因此这是“真正的节省”,可以帮助推销TDD的概念。

如果您可以清楚地证明所节省的时间,成本,代码和错误的价值,那么您会发现它更容易出售。


2

开始构建JUnit测试类是开始的方式,对于现有代码,这是唯一的开始方式。以我的经验,为现有代码创建测试类非常有用。如果管理层认为这会花费太多时间,则可以建议仅在发现相应的类包含错误或需要清理时,才编写测试类。

对于维护过程,使团队参与其中的方法是编写JUnit测试以在修复错误之前重现错误,即

  • 错误报告
  • 如果需要,创建JUnit测试类
  • 添加一个重现该错误的测试
  • 修正您的代码
  • 运行测试以显示当前代码不会重现该错误

您可以解释为通过以这种方式“记录”错误,可以防止这些错误稍后再出现。这是团队可以立即体验到的好处。


2

我已经在许多组织中做到了这一点,并且发现开始和遵循TDD的最佳方法就是建立结对编程。如果您还有其他人,可以依靠知道TDD的人,那么你们两个人可以分拆并与其他开发人员结对,以实际使用TDD进行一些配对编程。如果没有,我会训练一个可以帮助您做到这一点的人,然后再将其介绍给团队的其他成员。

单元测试(尤其是TDD)的主要障碍之一是开发人员不知道如何做,因此他们看不到如何值得花时间。同样,当您第一次入门时,它速度慢得多,似乎并没有带来任何好处。只有当您擅长时,它才能真正为您提供收益。通过设置配对的编程会话,您可以快速使开发人员能够快速学习它并更快地精通它。此外,当您一起工作时,他们将能够立即从中受益。

过去,这种方法对我有用了很多次。


2

发现TDD好处的一种有效方法是对某些现有功能进行重大重写,可能出于性能方面的考虑。通过创建一组可以很好地覆盖现有代码的所有功能的测试,这便使您充满信心地重构自己的内心内容,并完全确信所做的更改是安全的。

请注意,在这种情况下,我是在谈论测试设计或合同-测试实现细节的单元测试不适用于此处。但是话又说回来,TDD无法按定义测试实现,因为它们应该在实现之前编写。


1

TDD是开发人员可以用来生成更好的代码的工具。我碰巧觉得编写可测试代码的练习与测试本身一样有价值。出于测试目的隔离IUT(被测实现)会产生代码解耦的副作用。

TDD并非适合所有人,并且没有任何魔术可以吸引团队选择这样做。风险在于,不知道什么值得进行测试的单元测试作者将编写许多低价值的测试,这对于组织中的TDD怀疑论者来说是大炮。

我通常使自动验收测试不可商议,但允许开发人员采用适合他们的TDD。我有经验丰富的TDDers培训/指导其余人员,并在数月的时间内以身作则“证明”了其有用性。

这既是技术变革,又是社会/文化变革。

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.