我是一个单独的开发人员,拥有一个受时间限制的漂亮工作环境,每个项目的开发时间通常为1-4周,具体取决于需求,紧迫性或两者兼而有之。在任何给定的时间,我都会处理大约3-4个项目,其中一些项目的时间表相互重叠。

预期,代码质量会受到影响。我也没有正式测试;它通常会涉及到遍历整个系统,直到出现故障为止。结果,大量的错误逃逸到了生产环境中,我必须修复这些错误,然后又使我的其他项目受挫。

这是单元测试的地方。正确完成后,应该保留错误,更不用说那些逃到生产中的错误了。另一方面,编写测试可能要花费大量时间,对于像我这样的时间受限制的项目来说,这听起来并不好。

问题是,编写单元会花费多少时间差经过测试的代码而不是未经测试的代码,随着项目范围的扩大,时差如何扩大?

评论

评论不作进一步讨论;此对话已移至聊天。

您正在解决错误的问题。您太忙了,似乎没有项目管理支持。您是否正在估计项目工作量?您是否将20%的时间用于错误修复,会议和其他非编码任务?你要加班多少?

您是否意识到您实际上是在说“我有时间做两次,但没有时间做正确的一次。”?

@RubberDuck实际上在项目复杂度曲线中有一个点,以“写入时间与测试时间”来衡量,其中“拧两次”所需的时间少于“写入并进行测试”的时间。我认为它可能在bash oneliner区域中的某个地方。

有一次开发人员收到了礼物,并感谢项目被取消。我指出,如果我们知道该产品无法交付,我们本来可以提高生产力。因此,在这种情况下,无需测试即可进行开发。

#1 楼

测试越晚,编写测试的成本就越高。

错误的寿命越长,修复的成本就越高。

收益递减法则可以确保您可以测试自己以确保没有错误的遗忘。

佛陀教导了中间道路的智慧。测试很好。好东西太多了。关键是能够分辨出您何时失衡。

您编写的没有测试的每一行代码都会比稍后在编写代码之前编写测试要花费更多的时间来添加测试。 。

每行没有测试的代码将更加难以调试或重写。

您编写的每个测试都将花费时间。

每个错误都将需要时间修复。

忠实的信友会告诉您不要写一个无需先编写失败的测试的代码行。该测试可确保您获得预期的行为。它使您可以快速更改代码,而不必担心会影响系统的其余部分,因为测试证明了行为是相同的。

您必须权衡所有这些与测试未添加功能的事实之间的关系。 。生产代码添加了功能。功能是付账的。

从实用上讲,我添加了所有可以摆脱的测试。我无视观看测试的评论。我什至不相信代码会按照我的想法去做。我相信测试。但是众所周知,我偶尔会丢下冰雹玛丽,然后很幸运。

但是,许多成功的编码人员都不会进行TDD。那并不意味着他们不测试。他们只是不执着地坚持每行代码都有针对它的自动化测试。甚至Bob叔叔也承认他不测试自己的UI。他还坚持要求您将所有逻辑移出UI。

作为橄榄球的隐喻(即美式橄榄球),TDD是一项很好的地面比赛。仅在您编写一堆代码并希望它能正常工作的地方手动测试是一个过时的游戏。您都可以擅长。除非你们两人都能做到,否则您的职业生涯不会进入季后赛。除非您学习何时挑选每个,否则它不会成为超级碗。但是,如果您需要朝某个特定方向轻推,那么当我过世时,官员的电话经常会反驳我。

如果您想尝试一下TDD,我强烈建议您在尝试上班之前先练习一下。 TDD半途而废,三心二意,半驴子是一个不尊重它的重要原因。就像将一杯水倒入另一杯中。如果您不付诸行动,并且迅速而彻底地做到这一点,那末,您到处都是运球的水。

评论


一件好事太多了,无论您还是佛陀都没有测试过我祖母的饼干:-)

–皮埃尔·阿劳德
16年6月15日在13:05

@NickAlexeev我喜欢那里的图表。它没有指出的一件事是,单元测试(通常是自动化的)真的很擅长在修改代码时发现错误。我很乐意将其分为“发布前发现的错误”和“发布后发现的错误”。单元测试是防止回归的最佳方法。

– corsiKa
16年6月15日在15:44

我认为这是一个非常平衡的答案:测试所有内容,甚至是琐碎的事情,都可能浪费时间。对容易断裂的复杂零件进行良好的测试确实会有所帮助。我刚刚完成了从Java到C ++的移植,但并不简单。我首先移植了测试,这指导我设置了整个C ++实现。一旦所有测试都变成绿色,只需移植一些较简单的类即可,并且运行非常顺利。另一方面,我没有对所有代码进行测试:这将使实施至少延长3、4天,而收效甚微。

–乔治
16年6月15日在17:03

对此略有不同意见:“您必须权衡所有因素与测试未添加功能的事实。代码增加了功能。功能是付账的。”我强烈建议,不是功能付钱-它是有效的功能。 (或者人们是否因无法正常工作的交付物而获得报酬?)。我完全同意其余的答案。

–托尼·萨福克66
16年6月16日在20:06

@ TonySuffolk66你是正确的,这是工作功能付钱的(除非有flimflam销售技术)但是,人们早在TDD成为现实之前就已经创建了工作功能。他们会在它消失后很久的。记住,TDD是一种严格的测试方法。这不是唯一严格的测试方法。

–candied_orange
16年6月17日在3:38

#2 楼

我同意其余的答案,但直接回答时差问题是什么。

Roy Osherove在他的书《单元测试的艺术》(第二版)第200页中做了案例研究,以类似的方式实现针对两个不同的客户,使用相似的团队进行规模较大的项目(在技能上比较明智),其中一个团队进行了测试,而另一团队则没有。

他的结果是这样的:



因此,在项目结束时,您将获得更少的时间和更少的错误。当然,这取决于项目的规模。

评论


样本量太小,以至于不能认为这是科学的,但我认为这代表了很多人的经验。我发现执行TDD时,大部分额外时间都花在了修复导致单元测试失败的错误上,而不是自己编写测试。这实际上并没有增加额外的时间,只是在您发现并解决这些问题时进行了调整。任何真正的额外时间都在解决您不会发现的问题,至少在第一轮工作中没有。

– JimmyJames
16年6月15日在15:38

@JimmyJames这是一个案例研究,在尚无法进行大规模的可重复实验的情况下,在商业中广泛使用,在科学中也大量使用。有很多心理学期刊。 “不科学”不是正确的词。

–djechlin
16年6月16日在2:12

我为什么认为如果该案例研究的结果显示出相反的意思,就不会被纳入本书;-)?

–布朗博士
16年6月16日在10:40



@DocBrown我想知道有多少案例研究在找到正确答案之前被丢弃了:-)

– gbjbaanb
16年6月16日在12:13

@JimmyJames几乎可以肯定是科学。此外,另一位科学家可能会阅读“ n = 1”个案例研究,认为值得进一步研究,然后进行大规模的统计研究,甚至进行纵向对照实验,然后确认或拒绝。这正是科学的运作方式。那应该是这样的。您可以在此处详细了解科学的工作原理。en.wikipedia.org/ wiki / Scientific_method

–djechlin
16年6月16日在20:42

#3 楼

我只知道一项研究是在“实际环境”中进行的:通过测试驱动的开发实现质量改进:四个工业团队的结果和经验。以明智的方式进行此操作非常昂贵,因为这基本上意味着您需要与相似的团队一起开发同一软件两次(理想情况下甚至更频繁),然后将所有软件扔掉。

该研究的结果是,开发时间增加了15%–35%(与TDD评论家经常引用的2倍数字相去甚远),而释放前缺陷密度从40%–90%(! )。请注意,所有团队都没有使用TDD的经验,因此可以假设时间的增加至少可以部分归因于学习,因此时间会随着时间的流逝而进一步下降,但是这项研究并未对此进行评估。

请注意,此研究与TDD有关,而您的问题与单元测试有关,这是非常不同的事情,但这是我能找到的最接近的问题。

评论


施加额外的约束会更有趣:没有可变状态,遵循SOLID,静态类型,不依赖null,在命令中具有功能,代码协定,静态分析,自动重构,没有IoC容器(但DI)等。我敢打赌单元测试的值将减少(但不会消失)。

–丹
16年6月21日在13:12



#4 楼

做得好,即使不考虑捕获额外错误的好处,使用单元测试进行开发也可以更快。

事实是,我不是一个很好的编码器,无法尽快使我的代码工作它编译。当我编写/修改代码时,我必须运行代码以确保其能够达到我的预期。在一个项目中,这往往看起来像:


修改代码
编译应用程序
运行应用程序
登录到应用程序
打开一个窗口
从该窗口中选择一个项目以打开另一个窗口
在该窗口中设置一些控件,然后单击一个按钮

当然,毕竟,通常几次往返才能真正解决问题。

现在,如果我正在使用单元测试该怎么办?然后该过程看起来更像:


编写测试
运行测试,确保它以预期的方式失败
编写代码
再次运行测试,看看它通过了。

与手动测试应用程序相比,它更容易,更快捷。我仍然必须手动运行该应用程序(因此,当我上交实际上根本不起作用的工作时,我看上去并不傻),但是在大多数情况下,我已经解决了一些问题,而我只是此时进行验证。实际上,我通常使用一个保存时自动重新运行测试的程序来使此循环更加紧密。

但是,这取决于在易于测试的代码库中工作。许多项目,甚至那些具有许多测试的项目,也使编写测试变得困难。但是,如果您使用它,则可以拥有一个比自动测试更容易通过自动测试进行测试的代码库。另外,您可以保留自动化测试,并继续运行它们以防止回归。

评论


使用nCrunch之类的工具可以减少第2步和第4步,从而使反馈循环更加紧密。

– up
16年6月15日在7:22

恕我直言,“我仍然必须手动运行该应用程序”是一项重要的观察。没有银弹。

–丹
16年6月21日在13:18

#5 楼

尽管已经有了很多答案,但它们有些重复,我想换个角度。当且仅当它们增加了业务价值时,单元测试才有价值。为了测试的缘故而进行的测试(琐碎或重言式的测试)或达到任意度量标准(例如代码覆盖率),是一种容易受骗的编程。

测试是昂贵的,不仅是在编写时间上他们,而且维护。他们必须与他们测试的代码保持同步,否则就一文不值。更不用说在每次更改时运行它们的时间成本。那不是破坏交易(或不做真正必要的借口),但是需要在成本效益分析中加以考虑。

因此,在决定是否要进行时要问的问题(或哪种类型)来测试功能/方法,请问自己“我通过此测试可以创建/保护最终用户什么?”。如果您无法回答这个问题,那么该测试可能不值得花费编写/维护的费用。 (或者您不了解问题域,这比没有测试要严重得多)。

http://rbcs-us.com/documents/Why-Most-Unit-测试就是浪费.pdf

评论


我对BDD并不是很熟悉,但会猜测它的粒度比方法/函数级别的粒度略大,并且可能与用户值的联系不那么紧密。

–杰瑞德·史密斯(Jared Smith)
16年6月15日在15:32

有关

–罗比·迪(Robbie Dee)
16年6月15日在16:09

“为测试而进行的测试(琐碎或重言式的测试),或达到任意度量标准(如代码覆盖率)的测试,是一种易学的编程。”如此真实,如此善道。以这样的方式进行测试,使您感觉像是一个很酷的坏蛋-将自己视为……一个间谍,精英运动员……不要像“政府部门”那样进行测试。你懂?

–法蒂
16年6月16日在12:06

@SteveJessop不同意,代码覆盖率(就度量而言)本质上是任意的:在机器指令级别通过非平凡程序的路径数量(即计数的数量)将大于在其上的原子数量。地球甚至可能是可见的宇宙。这是不可测试的。因此,任何对“代码覆盖率”的主张都是某种启发式选择的任意阈值。程序员擅长以牺牲实际情况为代价来玩弄这样的指标。

–杰瑞德·史密斯(Jared Smith)
16 Jun 17'在12:35



我还要说的是,只要测试失败,测试就可以大致(尽管不是精确地)提供业务价值,解决方案是改进被测代码。因此,如果您使用的是TDD,则每个测试至少会自动发生一次。根据定义,重言式测试不会失败,因此是无用的。对于“琐碎”的测试-在我职业生涯的早期就使用Java TCK,对于从零开始重新实现API可能失败的琐碎测试,我不再感到惊讶;-)但是商业价值在于几乎总是凭经验来预测,“任意”也是如此。

–史蒂夫·杰索普(Steve Jessop)
16 Jun 20'在8:32



#6 楼

这取决于人员,以及所使用代码的复杂性和形状。

对我来说,在大多数项目中,编写单元测试意味着我可以将工作完成速度提高约25%。 。是的,甚至还包括编写测试的时间。

因为事实是编写代码时软件没有完成。当您将其运送给客户并且客户对此感到满意时,它就完成了。到目前为止,单元测试是捕获大多数错误,隔离大多数错误以进行调试以及使人们确信代码良好的最有效方式。无论如何,您必须要做这些事情,所以请做好。

评论


我认为值得一提,这是一项后天的技能。我看到很多人听到这样的说法,即TDD实际上甚至不是节省时间的预付款,从长远来看,它只是回报更快的时期。然后他们尝试了一天,这很痛苦,因为他们有0年的经验,读过0本书,没有练习,只是希望它能神奇地工作。 TDD并没有让您成为更好的开发人员的秘密,您仍然需要练习,仍然需要思考,仍然需要做出良好的决策。

–萨拉
16年6月15日在5:48

@kai-+1。在尝试之前,我花了数周时间阅读有关TDD的信息。我读了所有我能找到的东西。我读书。我通读了所有著名的敏捷博客作为示例。我从头到尾阅读了xUnit测试模式。在最初的几周里,我花了两倍的时间。

–法律
16年6月15日在8:33

我同意。 TDD很难。心态很难。任何说“只是先编写测试”并声称免费的人都不知道该怎么做。这需要练习。

–duffymo
16年6月15日在14:03

@kai:出于类似原因,很多人都无法触摸输入。他们尝试了一次,一个小时后仍然没有比以前更快地打字;-)

–史蒂夫·杰索普(Steve Jessop)
16年6月17日在1:05

@SteveJessop我想这是一个非常整洁的比较。或者是真的不健康,出去慢跑10分钟,精疲力尽,想知道为什么你不能在一小时内跑10英里。它确实说明了获得收益之前您需要如何工作。

–萨拉
16年6月17日在8:36

#7 楼

需要考虑的一些方面在其他答案中未提及。


额外收益/额外成本取决于编写单元测试的经验


单元测试项目的额外成本翻了三倍,因为我不得不学习很多东西,而且犯了很多错误。
在使用tdd十年后,我需要25%的编码时间来提前编写测试。


更多的tdd-moduls仍然需要手动进行gui-gui测试和集成测试
tdd仅在从一开始就可以使用。


将tdd应用于现有的,正在发展的项目非常昂贵/困难。但是您可以改为执行回归测试。


自动化测试(单元测试和其他类型的测试)需要maintanace const才能使其正常工作。


通过复制和粘贴创建测试可能会使testcode-maintanace变得昂贵。
随着经验的增长,testcode变得更加模块化且更易于维护。


随着经验的增长,您会感到什么时候值得创建自动化测试,何时不该创建自动化测试。


示例对简单的getter / setters / wrappers进行单元测试没有太大的好处
我不通过gui编写自动化测试
我要注意可以测试业务层



摘要

从tdd开始,很难达到“更多”只要您处于“时间紧迫的工作环境”中,就会发现“收益大于成本”状态
,特别是如果有“聪明的经理”告诉您“摆脱昂贵,无用的测试内容”

注意:带“ unit testi” ng”我的意思是“隔离测试模块”。

注意:“回归测试”是指


编写一些代码,生成一些输出文本。
编写一些“回归测试”代码,以验证生成结果仍然相同。
回归测试让您知道结果何时发生变化(可能还可以,也可能表明有新的错误)。
“回归测试”的概念类似于批准测试


...对结果进行快照,并确认结果没有改变。




评论


需要校对(等同于测试的文学水平?)

–JDługosz
16年6月19日在5:10

#8 楼

像处理大多数任务的人一样,程序员低估了完成任务实际上需要多长时间。考虑到这一点,可以花10分钟编写一个测试,因为实际上可以花大量时间编写大量代码,而实际上,您会花时间来编写与测试期间相同的函数名称和参数。 。这是TDD场景。

不编写测试,就像有一张信用卡一样。我们倾向于花费更多或编写更多代码。更多的代码具有更多的错误。

而不是决定是否覆盖全部代码或根本不覆盖代码,我建议重点关注应用程序的关键和复杂部分并在那里进行测试。在银行应用中,这可能是利息计算。发动机诊断工具可能具有复杂的校准协议。如果您一直在从事一个项目,则可能知道它是什么以及错误的位置。

慢慢开始。在判断之前要流利一些。您可以随时停止。

#9 楼


问题是,与未经测试的代码相比,编写经过单元测试的代码要花多少时间,随着项目范围的扩大,时间差如何扩大?


问题得到解决随着项目寿命的增加,情况变得更糟:因为每当添加新功能和/或重构现有实现时,都应该重新测试以前测试过的内容,以确保它仍然有效。
(多年期)项目,您可能不仅需要测试功能,还需要对其进行100次以上的测试。
因此,您可能会受益于自动化测试。
但是,IMO足够好了(甚至更好),如果它们是自动化的系统测试,而不是自动化的单元测试。

第二个问题是,如果不及早发现错误,可能很难发现和修复错误。例如,如果系统中存在一个错误,并且在您进行最新更改之前我知道它运行良好,那么我将集中精力于您的最新更改,以了解它可能是如何引入该错误的。但是,如果在进行最新更改之前我不知道该系统正在运行(因为在进行最新更改之前未对系统进行正确的测试),则该错误可能在任何地方。

上述内容特别适用于深层代码,而不适用于浅层代码,例如在新页面不太可能影响现有页面的情况下添加新网页。其他项目。


根据我的经验,这是不可接受的,因此您提出的问题是错误的。与其问测试是否可以使开发更快,还不如问什么可以使开发更加无错误。

更好的问题可能是:


是单位-测试正确的测试类型,您需要避免产生的“大量错误”?
是否还有其他建议或替代的质量控制/改进机制(除单元测试外)建议?

学习是一个分为两个阶段的过程:学习做得足够好,然后学习去做更快。

#10 楼

程序员委员会提倡TDD和其他测试方法已有很长的历史,我不会回想起他们的论点并同意他们的观点,但是这里有一些其他的考虑因素,应该有所细微之处:


根据上下文,测试并非同样方便,高效。我正在开发网络软件,告诉我您是否具有测试整个UI的程序...现在我正在编程excel宏,是否应该在VBA中真正开发一个测试模块?
编写和维护该测试软件是真正的工作在短期内很重要(从长期来看会有所回报)。编写相关的测试也是获得专业知识的一种方法。
团队合作和单独工作并没有相同的测试要求,因为在团队中,您需要验证,理解和交流您未编写的代码。 br />我说测试不错,但是请确保您尽早测试并测试增益在哪里。

评论


“我真的应该为VBA开发一个测试模块吗?”你该死的对。 rubberduckvba.com/Features#unitTesting

–RubberDuck
16年6月16日在23:23

我有几个理由不使用它,因为它不符合我的需求(我最多只能处理几天的任务,在锁定的环境中,后继者不会打扰第三方)。虽然很好的评论,语言本身并不是借口:)

– Arthur Hv
16年6月17日在6:25

所有公平点@ArthurHavlicek。

–RubberDuck
16年6月17日在10:02

在VBA中编写测试仍然微不足道。是否具有某些单元测试框架具有的所有奇特功能?那很难,但是运行一个调用mainTest()的程序来调用所有测试模块并不是真的那么难。

– enderland
16年6月17日在17:20

#11 楼

我可以与您的经验联系在一起-我们的代码库几乎没有测试,而且几乎无法测试。从字面上看,开发某些东西和修复产品错误花费了新功能的宝贵时间。

对于部分重写,我发誓要为所有核心功能编写测试。
一开始,它就花了更长的时间,我的生产力显着下降,但是后来我的生产力比以往任何时候都要好。

改进的部分原因是我减少了生产错误,从而减少了中断->我有了

此外,独立测试和调试代码的能力确实值得-一套测试远远优于只能通过手动设置才能进行调试的系统。 G。启动您的应用程序并导航至屏幕并执行某项操作……大概几十次了。

但是请注意,开始时生产率有所下降,因此请开始学习某个项目的测试,时间压力还不是很疯狂。另外,尝试在未开发的项目上启动它,对遗留代码进行单元测试非常困难,当您知道好的测试套件的外观时,它会有所帮助。

#12 楼

TDD经常被忽视的好处是,测试可以作为一种安全措施,以确保您在进行更改时不会引入新的错误。

TDD方法最初无疑会耗费更多时间,但要点是,您将编写更少的代码,这意味着更少的出错。当然,您通常会包括所有这些花哨的内容。

电影《剑鱼》中有一个场景,如果有记忆,黑客必须与之合作枪在他的头上,然后变得……否则会分散注意力。关键是,当您的代码中留有顶空并且您有时间在身边时,工作起来要容易得多,而不是几个月后客户就对您大叫而其他优先事项却受到挤压。

开发人员知道,以后修复错误的代价更高,但要立即解决。如果您每天可以得到500美元来编码现在的编码方式,或者如果您以TDD方式编写,则可以得到1000美元,那么您将使您成为第二笔报价的人。您越早停止将测试视为繁琐的工作并将其视为省钱的功能,您的生活就会越好。

评论


您第一句话中的那件事叫做回归测试

–猫
16年6月15日在11:06

#13 楼

只是为了补充先前的答案:请记住,测试本身并不是目的。进行测试的目的是使您的应用程序在不预期的上下文等情况下通过演化达到预期的行为。

因此,编写测试并不意味着证明实体所有端点的所有行为。这是一个常见错误。许多开发人员认为他们需要测试所有功能/对象/方法/属性/等。这导致大量的工作量以及大量不相关的代码和测试。这种方法在大型项目中很常见,在大型项目中,大多数开发人员并不了解整体行为,而只能看到他们的交互作用域。

处理稀疏资源和测试时正确的方法非常明显,并且有常识,但又没有正式形式化:首先将测试开发资源投入到高级功能上,然后逐步发展为特定功能。这意味着在某个时候,作为一个孤独的开发人员,您不仅会专注于单元测试,而且会专注于功能/集成/等。测试并根据您的时间资源,逐渐按照计划和考虑逐步进入主要的单一功能。高级测试将提供必要的信息,以解决低级/单一测试并根据您拥有的资源来规划您的测试开发策略。例如,您想测试一个处理链首先是黑匣子。如果您发现链中的某个成员由于未考虑某些极端条件的行为而失败,那么您可以编写测试以确保不仅在该成员上而且在其他成员上都具有功能。然后您交付。对于下一个周期,您检测到有时网络会失败。因此,您可以在可能易受攻击的模块上编写解决此类问题的测试。依此类推。