我正在努力将单元测试集成到我工作的团队的开发过程中,并且有一些怀疑论者.有什么好的方法可以让团队中持怀疑态度的开发人员相信单元测试的价值?在我的具体情况下,我们将添加单元测试,因为我们添加功能或修复了错误.不幸的是,我们的代码库不适合简单的测试.
我们办公室的每一天都有一个类似这样的交流:
"伙计,我只是喜欢单元测试,我只是能够对一些工作方式进行一些改变,然后能够通过再次运行测试确认我没有破坏任何东西......"
细节每天都在变化,但情绪却没有.单元测试和测试驱动开发(TDD)有很多隐藏的和个人的好处,以及你自己无法真正解释的明显的好处,直到他们自己做.
但是,忽略这一点,这是我的尝试!
单元测试允许您快速对代码进行大的更改.你知道它现在有效,因为你已经运行了测试,当你需要进行更改时,你需要让测试再次运行.这节省了数小时.
TDD可帮助您了解何时停止编码.你的测试让你相信你已经做了足够的事情,可以停止调整并继续下一步.
测试和代码协同工作以实现更好的代码.你的代码可能很糟糕/错误.你的测试可能很糟糕/错误.在TDD中,你可以看出两者都是坏的/错误的可能性很低.通常这是需要修复的测试,但这仍然是一个很好的结果.
TDD有助于编码便秘.如果面对大量艰巨的工作,写下测试将让你快速前进.
单元测试可以帮助您真正理解您正在使用的代码的设计.您不是编写代码来执行某些操作,而是首先概述您要对代码进行处理的所有条件以及您希望从中获得的输出.
单元测试为您提供即时的视觉反馈,当我们完成时,我们都喜欢所有绿灯的感觉.这非常令人满意.在中断之后离开的位置也更容易,因为你可以看到你需要去的地方 - 下一个需要修理的红灯.
与流行的观点相反,单元测试并不意味着编写两倍的代码,或编码速度较慢.一旦你掌握了它,它比没有测试的编码更快,更强大.测试代码本身通常是相对微不足道的,并不会给你正在做的事情增加很大的开销.这是你在这样做时才会相信的:)
我认为Fowler说:"不完美的测试,经常运行,比完全没有写过的完美测试要好得多".我将此解释为允许我编写测试,我认为它们将是最有用的,即使我的其余代码覆盖率非常不完整.
良好的单元测试可以帮助记录和定义应该做的事情
单元测试有助于代码重用.将代码和测试迁移到新项目.调整代码,直到测试再次运行.
我参与的很多工作都没有单元测试(Web应用程序用户交互等),但即便如此,我们都在本店测试感染,并且当我们的测试被绑定时最开心.我不能高度推荐这种方法.
单元测试很像去健身房. 你知道它对你有好处,所有的论点都有意义,所以你开始锻炼了.这是一个很好的初期热潮,但几天后你开始怀疑它是否值得这么麻烦.你需要一个小时的时间来换衣服,然后在仓鼠轮上跑步,你不确定除了腿部和手臂疼痛之外你还得不到任何其他东西.
然后,在一两周之后,就像疼痛消失一样,一个大截止日期即将开始.你需要花费每个醒着的时间来完成"有用"的工作,这样你就可以减少无关紧要的东西,比如去健身房.你没有这个习惯,当大截止日期结束时,你又回到原点.如果你设法让它回到健身房,你会感觉像第一次去的那样疼痛.
你做一些阅读,看看你做错了什么.你开始感到一点点非理性的厌恶,所有的健康,快乐的人颂扬运动的美德.你意识到你并没有很多共同之处.他们不需要开15分钟就可以去健身房; 他们的建筑物中有一个.他们不必与任何人争论运动的好处; 这只是每个人所做的事情并且接受同样重要的事情.当一个大截止日期临近时,他们不会被告知锻炼是不必要的,而不是你的老板会要求你停止进食.
因此,为了回答您的问题,单元测试通常是值得的,但所需的工作量对于每个人来说都不一样. 如果您在一家实际上并不重视代码质量的公司中处理意大利面条代码库,则单元测试可能需要付出巨大的努力.(许多管理人员会赞扬单元测试的赞誉,但这并不意味着他们会在重要的时候坚持下去.)
如果您正在尝试将单元测试引入您的工作中并且没有看到您所期望的所有阳光和彩虹,请不要责怪自己.您可能需要找到一份新工作才能真正让Unit Testing为您服务.
说服的最好方法...找一个bug,为它编写一个单元测试,修复bug.
那个特定的bug不太可能再次出现,你可以用你的测试证明它.
如果你做得足够好,其他人就会很快流行起来.
thetalkingwalnut问:
有什么好的方法可以让团队中持怀疑态度的开发人员相信单元测试的价值?
这里的每个人都会出于很多原因,为什么单元测试是好的.然而,我发现通常说服某人某事的最好方法是听取他们的论点并逐点解决.如果你倾听并帮助他们表达他们的担忧,你可以解决每一个问题,也许可以将它们转换为你的观点(或者至少让他们没有腿站立).谁知道?也许他们会说服你为什么单元测试不适合你的情况.不太可能,但可能.也许如果你发表反对单元测试的论据,我们可以帮助确定反驳.
倾听并理解论证的两个方面很重要.如果你试图过于热心地采用单位测试而不考虑人们的担忧,你最终会发生宗教战争(可能真的毫无价值的单位测试).如果你慢慢采用它并开始应用它,你将看到最低成本的最大利益,你可能能够证明单元测试的价值,并有更好的机会说服人们.我意识到这并不像听起来那么容易 - 通常需要一些时间和细致的指标来制定令人信服的论点.
单元测试是一种工具,与任何其他工具一样,应该以这样的方式应用,即利益(捕获错误)超过成本(编写它们的努力).如果/它们没有意义,请不要使用它们并记住它们只是您工具库的一部分(例如检查,断言,代码分析器,正式方法等).我告诉我的开发人员是这样的:
他们可以跳过为方法编写测试,如果他们有一个很好的论据,为什么没有必要(例如太简单不值得或太难以值得)以及如何验证方法(例如检查,断言) ,形式方法,交互/集成测试).他们需要考虑一些验证,如检查和形式证明,在某个时间点完成,然后每次生产代码更改时都需要重复,而单元测试和断言可以用作回归测试(写入一次并在此后重复执行) ).有时我同意他们,但更多时候我会争论一种方法是否真的太简单或太难以进行单元测试.
如果一个开发人员认为方法看起来太简单而不能失败,那么为它写一个简单的5行单元测试是否值得花60秒的时间?这5行代码将每晚运行(你做夜间构建,对吧?),对于明年或更长时间,即使只是一次碰到可能需要花费15分钟或更长时间来识别的问题,这些代码也是值得的.和调试.此外,编写简单单元测试可以提高单元测试的数量,从而使开发人员看起来很好.
另一方面,如果开发人员认为方法似乎太难以进行单元测试(不值得花费大量精力),也许这表明需要对方法进行划分或重构以测试简单部分.通常,这些方法依赖于异常资源,如单例,当前时间或外部资源(如数据库结果集).这些方法通常需要重构为获取资源的方法(例如,调用getTime())以及将资源作为参数的方法(例如,将时间戳作为参数).我让他们跳过测试检索资源的方法,然后他们为现在将资源作为参数的方法编写单元测试.通常,这使得编写单元测试变得更加简单,因此值得编写.
开发人员需要在他们的单元测试应该是多么全面的情况下画出"沙滩线".在开发的后期,每当我们发现错误时,他们应该确定更全面的单元测试是否会遇到问题.如果是这样,并且如果反复出现这样的错误,他们需要将"线"移动到将来编写更全面的单元测试(从添加或扩展当前错误的单元测试开始).他们需要找到合适的平衡点.
实现单元测试的重要性不是银弹,而是有太多的单元测试.在我的工作场所,每当我们吸取教训时,我都不可避免地听到"我们需要编写更多单元测试".管理层点头表示同意,因为它已经被"单元测试"="好"所左右.
但是,我们需要了解"更多单元测试"的影响.开发人员每周只能写出~N行代码,你需要弄清楚该代码应该是单位测试代码与生产代码的百分比.宽松的工作场所可能有10%的代码作为单元测试,90%的代码作为生产代码,导致产品具有很多(虽然非常多的)功能(想想MS Word).另一方面,一个拥有90%单元测试和10%生产代码的严格商店将拥有极少数功能的坚如磐石的产品(想想"vi").您可能永远不会听到关于后一种产品崩溃的报告,但这可能与产品的销售情况不同,因为它与代码的质量有很大关系.
更糟糕的是,也许软件开发中唯一确定的是"变化是不可避免的".假设严格的商店(90%单元测试/ 10%生产代码)创建了具有正好2个特征的产品(假设5%的生产代码== 1个特征).如果客户出现并更改了其中一项功能,则该更改将删除50%的代码(45%的单元测试和5%的生产代码).宽松的商店(10%单元测试/ 90%生产代码)具有18个功能的产品,其中没有一个能够很好地工作.他们的客户完全改变了他们4项功能的要求.尽管变化是4倍大,但只有一半的代码库被破坏(~25%= ~4.4%单元测试+ 20%的生产代码).
我的观点是,你必须要沟通,你才能理解在太少和太多的单元测试之间的平衡 - 基本上你已经考虑过问题的两个方面.如果你可以说服你的同行和/或你的管理层,你就会获得可信度,也许有更好的机会赢得他们.
我已多次玩过单元测试,但我仍然相信,鉴于我的情况,这是值得的.
我开发网站,其中许多逻辑涉及创建,检索或更新数据库中的数据.当我试图"模拟"数据库进行单元测试时,它已经非常混乱,似乎有点无意义.
当我编写关于业务逻辑的单元测试时,从长远来看它从来没有真正帮助过我.因为我主要在项目上工作,所以我倾向于直观地知道哪些代码区域可能会受到我正在处理的事情的影响,我会手动测试这些区域.我想尽快为我的客户提供解决方案,单元测试通常似乎是浪费时间.我列出了手动测试并自己走过它们,随时随地勾选它们.
我可以看到,当一个开发团队正在开发一个项目并更新彼此的代码时,这可能是有益的,但即便如此,我认为如果开发人员具有高质量,良好的沟通和编写良好的代码通常应该足够.
单元测试的一个好处是它们可以作为代码行为方式的文档.好的测试有点像参考实现,队友可以查看它们以了解如何将代码与您的代码集成.
单元测试非常值得初始投资.自从几年前开始使用单元测试以来,我发现了一些真正的好处:
回归测试消除了对代码进行更改的恐惧(没有什么比看到代码工作的温暖光芒或每次进行更改时都会爆炸)
其他团队成员的可执行代码示例(以及六个月后的自己......)
无情的重构 - 这是非常有益的,试试吧!
代码片段可以帮助您减少创建测试的开销.创建能够在几秒钟内创建类轮廓和相关单元测试夹具的片段并不困难.
你应该尽可能少地测试!
意思是,你应该编写足够的单元测试来揭示意图.这经常被掩盖.单元测试会花费你.如果您进行更改并且必须更改测试,那么您将不那么灵活.保持单元测试简短而甜蜜.然后他们有很多价值.
我经常看到许多测试永远不会破坏,大而笨拙并且没有提供很多价值,它们最终会让你失望.
我没有在任何其他答案中看到这一点,但我注意到的一件事是我可以更快地调试.您不需要通过正确的步骤深入了解您的应用程序以获取您修复的代码,只是发现您发生了布尔错误并需要再次执行此操作.通过单元测试,您可以直接进入正在调试的代码.
[我有一点让我无法看到上面]
"每个人都进行单元测试,他们不一定意识到这一点 - 事实"
想一想,你编写一个函数来解析一个字符串并删除换行符.作为一个新手开发人员,您可以通过在Main()中实现它来从命令行运行一些案例,或者将视觉前端与按钮组合在一起,将您的函数绑定到几个文本框和一个按钮,然后查看怎么了.
这是单元测试 - 基本和非常合理,但你测试了一些代码的代码.
你写的东西更复杂.当您抛出一些案例(单元测试)并调试代码并进行跟踪时,它会抛出错误.你在经历时会看到价值观,并决定它们是对还是错.这在某种程度上是单元测试.
这里的单元测试实际上是采取这种行为,将其形式化为结构化模式并保存,以便您可以轻松地重新运行这些测试.如果你写一个"正确的"单元测试用例而不是手动测试,它会花费相同的时间,或者你经验丰富的时候可能更少,并且你可以一次又一次地重复
多年来,我试图说服人们他们需要为他们的代码编写单元测试.无论他们是首先编写测试(如在TDD中)还是在编写功能之后,我总是试图向他们解释为代码进行单元测试的所有好处.几乎没有人不同意我的观点.你不能不同意明显的事情,任何聪明的人都会看到单元测试和TDD的好处.
单元测试的问题在于它需要行为改变,而且很难改变人们的行为.用语言,你会得到很多人同意你,但你不会看到他们做事的方式有很多变化.
你必须通过这样做来说服人们.你的个人成功将吸引更多的人,而不是你可能拥有的所有论点.如果他们发现你不只是在谈论单元测试或TDD,而是你正在做你所宣讲的,并且你成功了,人们会试着模仿你.
您还应该担任主角,因为没有人在第一时间正确编写单元测试,因此您可能需要指导他们如何执行此操作,向他们展示方式以及可用的工具.在他们编写第一次测试时帮助他们,查看他们自己编写的测试,并向他们展示您通过自己的经历学到的技巧,习语和模式.过了一段时间,他们将开始自己看到好处,他们将改变他们的行为,将单元测试或TDD纳入他们的工具箱.
变化不会在一夜之间发生,但只要有一点耐心,您就可以实现目标.
经常被掩盖的测试驱动开发的一个主要部分是编写可测试代码.它起初似乎是一种妥协,但你会发现可测试的代码最终也是模块化的,可维护的和可读的.如果您仍然需要帮助说服人们这是一个关于单元测试优势的简单介绍.
如果您现有的代码库不适合单元测试,而且它已经在生产中,那么您可能会通过尝试重构所有代码来创建比解决方案更多的问题,以便它可以进行单元测试.
您可能最好还是努力改进集成测试.有很多代码在没有单元测试的情况下编写起来更简单,如果QA可以根据需求文档验证功能,那么就完成了.装运它.
在我看来,这个经典的例子是嵌入在链接到GridView的ASPX页面中的SqlDataReader.代码全部在ASPX文件中.SQL位于存储过程中.你有什么单元测试?如果页面完成它应该做的事情,你真的应该把它重新设计成几层,这样你就可以自动化吗?
One of the best things about unit testing is that your code will become easier to test as you do it. Preexisting code created without tests is always a challenge because since they weren't meant to be unit-tested, it's not rare to have a high level of coupling between classes, hard-to-configure objects inside your class - like an e-mail sending service reference - and so on. But don't let this bring you down! You'll see that your overall code design will become better as you start to write unit-tests, and the more you test, the more confident you'll become on making even more changes to it without fear of breaking you application or introducing bugs.
对您的代码进行单元测试有几个原因,但随着时间的推移,您会发现节省测试时间是执行此操作的最佳理由之一.在我刚刚交付的系统中,尽管声称我花费更多时间进行测试而不是手动测试系统,但我坚持进行自动化单元测试.完成所有单元测试后,我在不到10分钟的时间内运行了400多个测试用例,每次我不得不对代码进行一些小的更改,我只需要确保代码仍在运行,没有错误就是十分钟.你能想象用手动这400多个测试用例的时间吗?
当涉及到自动化测试 - 无论是单元测试还是验收测试 - 每个人都认为,如果您计划仅运行一次测试,那么手动编写可以执行的操作就会浪费精力,有时这是真的.自动化测试的最佳部分是您可以毫不费力地运行它们几次,并且在第二次或第三次运行之后,您浪费的时间和精力已经付清.
最后一条建议是不仅要对代码进行单元测试,还要先开始测试(有关更多信息,请参阅TDD和BDD)
在重构或重写代码时,单元测试也特别有用.如果你有良好的单元测试覆盖率,你可以放心地重构.没有单元测试,通常很难确保你没有破坏任何东西.
简而言之 - 是的.他们值得每一分努力......到了一定程度.在一天结束时,测试仍然是代码,就像典型的代码增长一样,您的测试最终需要进行重构才能实现可维护性和可持续性.有一吨GOTCHAS!当涉及到单元测试时,但男人哦,男人,男人,什么都没有,我的意思是没有让开发人员能够比一组丰富的单元测试更自信地进行更改.
我现在正在开展一个项目......它有点像TDD,而且我们的大部分业务规则都被认为是测试...我们现在有大约500个左右的单元测试.在过去的迭代中,我不得不改进我们的数据源以及我们的桌面应用程序如何与该数据源进行交互.花了几天时间,我一直在进行单元测试,看看我打破了什么并修好了.做出改变; 构建并运行测试; 修复你破坏的东西.洗涤,冲洗,必要时重复.传统上需要几天的质量保证和船只压力是一个简短而愉快的体验.
事先做好准备,做一点额外的努力,当你不得不开始使用核心功能/功能时,它可以支付10倍的费用.
我买了这本书 - 它是xUnit测试知识的圣经 - 这可能是我书架上参考最多的书之一,我每天都会查阅它: 链接文字
偶尔我自己或我的一个同事会花费几个小时到达稍微模糊的bug的底部,一旦发现错误的原因,90%的时间代码未经过单元测试.单元测试不存在,因为开发人员正在偷工减料以节省时间,但随后又失去了这个和更多的调试.
花费少量时间编写单元测试可以节省未来几小时的调试时间.
我是一名维护工程师,负责一个记录不完整,可怕且代码量大的代码库.我希望编写代码的人编写了单元测试.
每次我做出更改并更新生产代码时,我都害怕我可能会因为没有考虑某些条件而引入错误.
如果他们编写测试,那么对代码库的更改将更容易,更快.(同时代码库将处于更好的状态).
我认为单元测试在编写必须持续多年的api或框架以及由原始编码器以外的人使用/修改/演化时证明非常有用.
单元测试绝对值得付出努力.不幸的是,您选择了一个难以(但不幸的是常见)的方案来实现它.
您将获得的单元测试的最大好处是从头开始使用它 - 在一些选择的小项目中,我有幸在实现我的类之前编写单元测试(接口已经完成了点).通过适当的单元测试,您可以在课程中找到并修复错误,同时它们仍处于初级阶段,而不是在复杂系统附近的任何地方,它们无疑将在未来集成.
如果您的软件是面向对象的,那么您应该能够在课堂级别添加单元测试而无需太多精力.如果您不是那么幸运,您仍应尝试在任何地方进行单元测试.确保在添加新功能时,新的部件已经通过清晰的界面进行了明确定义,您会发现单元测试可以让您的生活更轻松.
当你说,"我们的代码库不适合轻松测试"是代码味道的第一个迹象.编写单元测试意味着您通常以不同的方式编写代码,以使代码更易于测试.在我看来,这是一件好事,因为我多年来在编写代码时已经看到了我必须编写的测试,这迫使我提出了更好的设计.
我不知道.很多地方不做单元测试,但代码质量很好.微软确实进行了单元测试,但比尔盖茨在他的演讲中给出了蓝屏.
我写了一篇关于这个主题的非常大的博客文章.我发现单独的单元测试不值得工作,并且在截止日期越来越近时通常会被削减.
我们不应该从"测试后"验证的角度讨论单元测试,而应该看看在开始实现之前编写规范/测试/想法时发现的真正价值.
这个简单的想法改变了我编写软件的方式,我不会回到"旧"的方式.
如何测试第一次发展改变了我的生活