TDD与unit testing

我的公司对于unit testing我们的代码是相当新的。 我一直在阅读关于TDD和unit testing一段时间,并确信它们的价值。 我试图说服我们的团队,TDD值得努力学习和改变我们的思维方式,但是这是一场艰苦的斗争。 这使我想到了我的问题。

TDD社区有很多人对编写testing和代码非常虔诚(而且我和他们在一起),但对于一个正在与TDD苦苦挣扎的团队来说,妥协还是会带来额外的好处?

一旦编写代码,我可能成功地让团队编写unit testing(也许作为签入代码的要求),我的假设是编写这些unit testing还是有价值的。

把一个挣扎的团队带进TDD的最好方法是什么? 如果失败了,即使是在编写代码之后,仍然值得编写unit testing吗?

编辑

我从中得到的是,在编码过程中,对我们来说开始进行unit testing是非常重要的。 对于那些拾取概念的团队来说,开始更多地走向TDD并首先进行testing。 感谢大家的意见。

跟进

我们最近开始了一个新的小项目,一小部分使用了TDD,剩下的则是在代码之后写unit testing。 在完成了项目的编码部分之后,那些编写代码的unit testing人员惊讶地发现TDD编码器已经完成了,代码更加稳定。 这是一个赢得怀疑者的好方法。 我们仍然有很多成长的痛苦,但遗嘱战似乎已经结束了。 感谢所有提供build议的人!

如果团队在执行TDD时遇到困难,但是他们之前没有创build任何unit testing,那么在编写代码之后通过创buildunit testing来启动它们。 即使在代码之后编写的unit testing都比没有unit testing更好!

一旦他们精通unit testing(以及与之相关的一切),那么您可以先让他们创buildtesting,然后再编写代码。

代码编写完成后unit testing还是值得的。 只是有时候这样做通常比较困难,因为你的代码没有被devise为可testing的,而且你可能已经过于复杂了。

我认为把团队纳入TDD的一个好的务实方法是在过渡期或者可能长期提供替代的“发展中testing”方法。 应该鼓励他们对TDD部分代码看起来很自然。 然而,在看似难以接近“先testing”的代码段中,或者在使用由非敏捷A&D过程预先定义的对象的代码段中,开发人员可以select编写一小段代码,然后编写testing来覆盖代码,并重复这个过程。 编写单元在编写代码之后立即testing一些代码比根本不写任何unit testing要好。

在我看来,最好有50%的testing覆盖率,“代码优先,testing完成”和100%完成的库,比100%的testing覆盖率和50%完成的TDD库。 过了一段时间,您的开发人员希望能够为他们编写的所有public代码编写testing程序,从而获得娱乐性和教育性,因此TDD将潜入到开发过程中。

我只是在一个日历上读到这样的话:“每一个被执行的规则都是荒谬的,甚至是危险的。” 所以我的build议是不要虔诚的。 你们团队中的每个成员都必须在涉及到testing的时候觉得“正确”。 这样,你们团队中的每个成员都将是最有成效的(而不是说,为什么我必须写这个testing?)。

所以有些testing总比没有好,代码testing之后的代码优于less数testing,testing之前代码比之后更好。 但是每一步都有自己的优点,你不应该皱眉,甚至小步。

TDD是关于devise的! 所以,如果你使用它,你一定会有一个可testing的代码devise,使编写testing变得更容易。 如果你在编写代码后编写testing,他们仍然是有价值的,但恕我直言,你会浪费时间,因为你可能没有一个可testing的devise。

我可以给你一个build议,试图说服你的团队采用TDD,它使用了Mary Linn和Linda Rising所描述的一些技巧:引入新思想的模式

如果他们对testing比较陌生,那么IMO就会开始testing已经写好的代码,然后慢慢地从gradle后开始写testing。 正如有人试图学习TDD和unit testing新手一样,我发现做一个完整的testing很困难,并改变了我的心态,在代码之前编写testing,所以我采取的方法是50-50混合; 当我确切地知道代码是什么样子的时候,我会写代码然后编写一个testing来validation它。 对于那些我不完全确定的情况,我会从testing开始,然后反向工作。

另外请记住,编写testing来validation代码没有任何问题,而不是编写代码来满足testing。 如果你的团队不想走TDD路线,那么不要强迫他们。

一旦编写代码,我可能成功地让团队编写unit testing(也许作为签入代码的要求),我的假设是编写这些unit testing还是有价值的。

毫无疑问,在unit testing代码中是有价值的(不pipe何时写testing),并且在“定义完成”中包含“代码是unit testing的”。 只要他们testing,人们可以使用TDD或不使用TDD。

关于版本控制,我喜欢使用带有unit testing策略的“ 开发分支 ”(即代码编译和构build,所有unit testing通过)。 当function完成后,它们从开发分支发布到主干。 换句话说,干线分支是“ 完成分支 ”(干线上没有垃圾!),并且有一个比“unit testing”更严格的包括更多东西的可发货政策(可以在任何时候发布)。

这是你的团队必须有自己的成功之前,他们开始相信英寸我会咆哮关于我的nUnit顿悟为任何关心的人:

大约5年前,我在一个项目上工作时发现了nUnit。 我们几乎完成了V1.0,我创build了一些testing来试用这个新工具。 我们有很多错误(显然!),因为我们是一个新的团队,在紧迫的期限内,期望值很高(听起来很熟悉?)等等。无论如何,我们得到了1.0,并开始在1.1。 我们重新组build了这个团队,并且把2个开发者分配给了我。 我为他们做了一个1小时的演示,告诉他们我们写的所有东西都必须有一个testing用例。 我们经常在1.1开发周期中“落后”其他团队,因为我们正在编写更多的代码,unit testing。 我们结束了更多的工作,但是这是我们的收获 – 当我们最终进入testing阶段时,我们的代码中只有0个错误。 我们帮助其他人debugging和修复他们的错误。 在尸检中,当虫虫数量出现时,引起了大家的关注。

我并不认为自己可以通过testing来获得成功,但在unit testing方面,我是一个真正的信徒。 该项目通过nUnit,并由于1个成功,很快传播到所有.Net项目的公司。 我们V1.1发布的总时间是9个星期,所以绝对不是一朝一夕的成功。 但长期来看,我们的项目和我们为其构build解决scheme的公司certificate是成功的。

毫无疑问,testing(首先,同时甚至之后)将会保存您的培根,并提高您的生产力和信心。 我build议采用它!

我也遇到过类似的情况,因为我是一个“noob”的开发者,在团队项目的工作中,我经常感到沮丧,因为贡献打破了构build。 我不知道我是否应该受到指责,甚至在某些情况下应该责怪谁。 但是我更关心的是,我正在向同行开发者做同样的事情。 然后这个实现动机采取一些TDD战略。 我们的团队开始有愚蠢的游戏和规则,就像你不能回家直到所有的testing通过,或者如果你没有testing提交的东西,那么你必须购买每个人“啤酒/午餐等”,这使得TDD更有趣。

unit testing的一个最有用的方面是确保已经工作的代码的持续正确性。 当您可以随意重构时,让IDE提醒您编译时错误,然后单击一个button,让您的testing发现任何潜在的运行时错误 – 有时会到达以前不重要的代码块,然后我认为您会发现您的团队开始欣赏TDD。 所以从testing现有的代码开始肯定是有用的。

另外,坦率地说,我已经学会了更多的关于如何编写可testing的代码,而不是从TDD开始testing代码。 如果您想要考虑能够达到最终目标并允许testing的合同,那么起初可能太抽象了。 但是当你看代码并且可以说“这个单例在这里完全破坏dependency injection并且使testing变得不可能”时,你开始理解什么样的模式让你的testing变得更容易。

那么,如果你不先写testing,它不是“testing驱动”,它只是testing。 它本身就有好处,如果你已经有了一个代码库,那么添加testing对于它来说是非常有用的,即使它不是TDD,而只是testing。

首先写testing是关注代码在写代码之前应该做些什么。 是的,你也做了这样的testing,这是好的,但有些人可能会认为这甚至不是最重要的一点。

我要做的就是使用TDD(如果能让有经验的TDD程序员参加这样的研讨会,会更好)对这类玩具项目 (请参阅Coding Dojo,Katas)进行培训。 当他们看到他们将使用TDD的实际项目的好处时。 但同时不要强迫他们,他们没有看到他们不会做得对的好处。

如果您在编写代码之前进行了devise会议,或者必须制作devise文档,那么您可以添加unit testing作为会议的实际结果。

这可以作为您的代码如何工作的规范。 鼓励在devise会议上进行配对,让人们讨论在某些场景下应该如何工作以及应该做些什么。 什么是边缘情况,对它们有明确的testing用例,所以如果给定一个空参数,每个人都知道它会做什么。

除了BDD,也可能是有趣的

你可能会发现一些例子,TDD导致代码写得less,因为你只写代码来使testing通过,诱惑金牌或从事YAGNI更容易抵抗。 你不写的代码不需要维护,重构等,所以这是一个“真正的节省”,可以帮助销售TDD的概念。

如果您可以清楚地展示保存的时间,成本,代码和错误的价值,您可能会发现它更容易销售。

开始构buildJUnittesting类是开始的方式,对于现有的代码来说,它是唯一的开始。 根据我的经验,为现有代码创buildtesting类非常有用。 如果pipe理层认为这会投入太多时间,那么当相应的类被发现包含错误或需要清理时,可以build议只编写testing类。

对于维护过程来说,让团队超越线的方法是编写JUnittesting来重新修复它们之前的错误,即

  • 错误报告
  • 根据需要创buildJUnittesting类
  • 添加一个重现错误的testing
  • 修复你的代码
  • 运行testing以显示当前的代码不会重现该错误

你可以这样解释,通过这种方式“logging”错误可以防止这些错误在以后出现。 这是一个团队可以立即体验的好处。

我已经在许多组织中做了这个工作,我发现开始和遵循TDD的最好方法就是build立结对编程。 如果你有其他人,你可以依靠那个知道TDD的人,那么你们两个可以分手,并与其他开发人员配对,实际上使用TDD进行一些配对编程。 如果不是的话,我会训练一个能帮助你做这件事的人,然后把它交给其他人。

unit testing,特别是TDD的主要障碍之一是开发人员不知道如何去做,所以他们不知道如何值得他们的时间。 另外,当你第一次开始,它是慢得多,似乎并没有提供好处。 只有当你擅长的时候,才真正为你提供了好处。 通过设置配对的编程会话,您可以快速地让开发人员快速学习,并更快地学习。 另外,当你在一起工作时,他们将能够立即看到它的好处。

过去这种方法对我来说已经有很多次了。

发现TDD优势的一个强有力的方法是对性能上的原因做一些重要的改进。 通过创build一套能够覆盖现有代码所有function的testing,您可以充满信心地重构您内心的内容,从而使您的安全得到改变。

请注意,在这种情况下,我正在讨论testingdevise或合同 – testing实现细节的unit testing在这里不适合。 但是TDD不能按照定义来testing实现,因为它们应该在实现之前编写。

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

TDD不适合每个人,也没有什么魔法可以让团队select这样做。 风险在于不知道什么是值得testing的unit testing编写者会写出很多低价值的testing,这将是组织中TDD怀疑者的炮灰。

我通常使自动化验收testing不可谈判,但允许开发人员采用TDD,因为它适合他们。 我有经验丰富的TDD培训/辅导其余部分,并通过几个月的例子“certificate”有用。

这是一个技术性的社会/文化变革。