饮食、睡眠和呼吸单元测试/TDD/BDD [关闭]
Posted
技术标签:
【中文标题】饮食、睡眠和呼吸单元测试/TDD/BDD [关闭]【英文标题】:Eat, Sleep and Breathe Unit Testing/TDD/BDD [closed] 【发布时间】:2010-12-09 14:54:27 【问题描述】:我在编写 API 和核心功能时会编写单元测试。但我想成为吃、睡和呼吸 TDD 和 BDD 的酷迷。以正确的方式开始使用 TDD/BDD 的最佳方式是什么?有什么书籍、资源、框架、最佳实践吗?
我的环境是带有 Grails 前端的 Java 后端,与多个外部 Web 服务和数据库集成。
【问题讨论】:
网络测试很难。您不可避免地需要测试视图代码,并且有太多人试图通过测试原始 html 中是否存在字符串来做到这一点。那只是一团糟。最好使用 Selenium 等主要在集成测试中测试视图代码。 【参考方案1】:阅读博客是一个很好的起点。然后买写博客的人的书。我强烈推荐一些:
“鲍勃叔叔”马丁和 Object Mentor 的伙计们: http://blog.objectmentor.com/
附:获取 Bobs 的书清洁代码:
http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882
我的朋友 Tim Ottinger(前 Object Mentor 兄弟) http://agileinaflash.blogspot.com/ http://agileotter.blogspot.com/
Jetbrains 伙计们: http://www.jbrains.ca/permalink/285
我觉得有必要对此进行扩展,因为其他人似乎只是想给你他们对 TDD 的看法,而不是帮助你成为绝地忍者。 TDD 的迈克尔乔丹是肯特贝克。他确实在上面写过书:
http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530
他还写博客:
http://www.threeriversinstitute.org/blog/?p=29
TDD 的其他“著名”支持者包括:
Tim Bray Martin Fowler Ward Cunningham所有人都是值得追随的好人。您还应该考虑参加一些会议,例如 Agile 2010 或 Software Craftsmanship(今年它们在芝加哥同时举行)
【讨论】:
这就是我要找的。span> agileinaflash.blogspot.com/2009/02/meaningful-names.html 是缩写形式。是的,莱伯是我的朋友。【参考方案2】:我不喜欢人们说“练习 X 从来都不是坏事;如果它不起作用,那就是你做得不对。”抱歉,它与任何其他过分热心的宗教教条具有相同的感觉。我不买。
我同意那些说您的时间和金钱可以负担得起的最佳解决方案应该是目标的人的观点。
不应自动指责任何反对 TDD 的人忽视质量。 (“那么你什么时候停止打你的妻子了?”)事实上,软件中存在缺陷,消除所有缺陷的成本必须与收益相权衡。
制造业也是如此。尺寸公差和表面光洁度并不完全相同,因为有时不能保证紧公差和镜面光洁度。
是的,我编写单元测试,尽管在编写课程之前并不经常。我已经看到了测试对设计的影响。我测量并观察代码覆盖率。如果我发现我的覆盖率不可接受,我会编写更多测试。我了解用于重构的单元测试安全网的好处。即使我独自工作,我也会遵循这些做法,因为我亲身体验了这些好处。我明白了。
但我会怀疑任何开始在“吃、睡和呼吸单元测试和 TDD”问题上困扰我的队友。
我的经理说,让我升职的唯一方法是让团队达到 TDD/BDD。
有没有想过这会让你听起来像个傻逼?您是否发现您的唠叨已经疏远了团队的其他成员?
这个回复可能会让我失去一些声望点,但必须说出来。
我认为更好的方法是自己练习并让其他人看到好处。以身作则。这比嘴上说的更有说服力。
天哪,Grails 内置了测试生成功能。如果您在使用 Grails 的团队工作,还需要多少销售?
【讨论】:
+1 你不会因为这样说而失去一分。我在讽刺“吃、睡和呼吸 TDD”,因为我的经理更痴迷于 TDD 这个流行词而不是产品质量。 对不起,讽刺和讽刺被我的浏览器过滤掉了。我误解了你的意图。 取决于他们如何反对 TDD。如果你是“吃、睡、睡”测试,我会说你的注意力集中在错误的事情上。但是 TDD 不是测试。 TDD 是一个完整的开发过程,假设你不介意你的一生都在开发,我对那些说他们想要“吃、睡和睡” TDD 的人没有任何问题。尽管讽刺。 顺便说一句,TDD 无法真正解决许多问题领域。以游戏开发为例。您可以对游戏中的大量内容进行单元测试,但仍有大量代码几乎无法测试。这给 TDD 的工作带来了麻烦。 我个人的经验是,我在库代码上的 TDD 比 Web 应用程序代码(我的两个主要工作领域)的结果要好 3 倍,所以可以说 TDD 的好处是分布不均。不同的应用有不同的测试需求。但是,我还没有做一些我觉得 TDD 是浪费时间的事情。 (至少自从我开始很好地做 TDD 以来;一开始有点痛苦。)【参考方案3】:最佳实践恕我直言:做实际的事情,而不仅仅是因为它是一个过程。不要忘记编写应用程序的目标是什么,在商业世界中,它不是编写测试。不要误会我的意思,他们有自己的位置,但这不应该是目标。
【讨论】:
从来没有做过好 TDD 的人总是给出这个建议。有时他们已经这样做了,但经过进一步调查,很明显他们所做的更像是bad TDD,而且他们的大部分问题都源于不良实践而不是 TDD 本身。 你明白了,我猜我从来没有真正做过任何“真正的”TDD。实际上,我所说的是,正确使用它们确实会提供价值,但您必须小心,您的重点是提供解决方案,而不仅仅是编写测试。 恕我直言(以及许多比我聪明的人的 HO)如果您没有测试,那么您根本就没有工作代码。测试并不是一件好事,它们是必需品和要求。当然,除非您喜欢拥有较长的开发周期、没有人知道它是如何工作的错误代码以及整个 QA 部门的工作人员。 天哪,在 TDD 之前我们做了什么? @wilums2 在我们拥有汽车之前,我们使用的是马车。没有多少人会说马车比汽车更有效:)【参考方案4】:找到一直在做 TDD/BDD 的人,并与他们结对编程。
【讨论】:
【参考方案5】:恕我直言,指标是从这里到那里的最佳方式。跟踪您的代码被覆盖的程度,为每次提交保留代码复杂度的增量,使用测试运行程序来监视您的代码的更改并不断地重新运行相应的测试。永远不要让测试长度超过几行,这样你的所有工具都可以正常工作。我建议每月一次,请一天假通过突变测试器运行您的代码。那天应该专门用于编写测试。如果你还没有做好 TDD,所有这些东西都会给你带来痛苦。从痛苦中吸取教训,很快你就会做对了。
永远不要忽视测试的目的:描述期望的行为。它们是您的可执行规范。 (这也是我喜欢Cucumber 的原因;现在您可以让您的 PHB 为您编写测试!好吧,也许不是那么好,但已经接近了!)
【讨论】:
+ 1 "永远不要忘记测试的目的:描述期望的行为。" 您能推荐任何突变测试仪吗? Heckle、Pester、Jester 分别用于 Ruby、Python 和 Java。 Cucumber 链接+1,非常有趣!【参考方案6】:“PS:我的经理说,让我升职的唯一方法是让团队达到 TDD/BDD。”
让团队做某事(不会在此过程中杀死你)的唯一现实方法是向他们清楚地表明改变习惯将有益于他们。换句话说,写代码。很多代码。大量的代码。然后,当重要的电子邮件从根本上改变规范时,向他们展示您可以通过重构轻松更改代码,更糟糕的是,因为您已经为它准备并进行了测试。酒吧是绿色的,hack hack hack,RED BAR!!!!,hack hack hack,绿色酒吧,回家吧。
阅读 Kent Becks 关于测试驱动设计的书。从测试开始,然后编写代码。获取运行测试的构建服务器!您不需要为整个团队都拥有它 - 为自己做它并向他们展示它有帮助。
讲道只会惹恼当地人:)
【讨论】:
【参考方案7】:我从事 TDD 已经有几年了,但最近我开始更多地关注 BDD 驱动我的设计和开发的方式。帮助我开始 BDD 的资源首先是 Dan North 的博客(BDD 的“创始人”)。看看Introducing BDD。在behaviour-driven.org 上还有一个“官方”BDD Wiki,其中有一些值得一读的好帖子。
在开始使用 BDD 时,我发现真正困难的一件事(并且仍然觉得有点困难)是如何制定这些场景以使其适合 BDD。 Scott Bellware 是一位精通 BDD(或他喜欢创造的 Context-Spesification)的人,他在 Code Magazine 上的文章 Behavior-Driven Development 在理解 BDD 的思维方式和制定用户故事方面帮助了我很多。
我还会推荐 Rob Conery 的 TekPub 截屏视频Behavior-driven Design with Specflow。 BDD 和非常适合在 C# 中执行 BDD 的工具 (SpecFlow) 的精彩介绍。
至于 TDD 资源,这里已经有很多不错的推荐。但我只想指出几本书,我真的可以推荐;
Working Effectively with Legacy Code迈克尔·费瑟斯;如果您正在处理遗留代码(我们不都是吗?)并希望对其进行测试,则必须阅读此书 The Art of Unit Testing: With Examples in .Net 罗伊·奥舍罗夫;如果您不熟悉单元测试,这是帮助您入门的书 Test Driven Development: By Example 肯特贝克;如果您正在学习 TDD,为什么不从源代码本身获取它呢?一本好书 - 易于阅读、幽默和伟大的思想。 Clean Code: A Handbook of Agile Software Craftsmanship Robert C. Martin;如果 Kent Beck 描述了 TDDhows,那么 Uncle Bob 描述了whys。【讨论】:
【参考方案8】:首先要开始进行单元测试,然后阅读有关如何正确执行的信息,最后教您的团队如何进行 TDD 并让他们参与进来 - 因为根据我的经验,没有什么比与整个团队一起进行单元测试更重要的了。
您还需要一个适当的构建过程 - 使用构建服务器来构建您的代码并运行您的测试,我建议使用 TeamCity(免费但有限制)。
学习如何正确地进行良好的单元测试是困难的部分——其中一些你会自己学习(只要你坚持单元测试),其余的你可以通过搜索互联网来学习。
如果不编写单元测试作为开发的一部分,你就会知道你已经达到了目标。
【讨论】:
我们确实有一个构建过程和一些测试,但这些都是外包的。【参考方案9】:请记住,敏捷意味着您不会完全放弃任何特定方法。如果您正在做的事情不值得 TDD 的好处(例如在 Swing 界面上进行试错编辑),那么不要使用 TDD。
【讨论】:
TDD 是否总是必须成为敏捷的一部分? 我认为敏捷意味着我们在纸面上没有任何要求,项目经理可以来我的办公桌,让我随时添加这个或那个小功能。跨度> 哈哈,这就是一些项目经理想要的。但是没有。【参考方案10】:我看不出有人真正表示 TDD 不是关于测试的。 TDD-ing 是在进行微小的行为改变修改之前表达预期的行为。这极大地改进了设计,并以我以前从未体验过的方式实现了专注。您可以免费获得保护您未来重构和 90% 覆盖率的测试。
要学习它,我建议(总结其他人所说的并添加我自己的):
-
访问博客并阅读上述书籍
与精通 TDD 的人配对
练习
在我开始看到光之前,我自己练习了大约 20 次(每次大约 30 分钟)保龄球 kata(练习)。首先分析鲍勃叔叔对它的描述here。在 codingdojo.org 网站上有很多 katas,包括解决方案和讨论。试试看!
【讨论】:
【参考方案11】:引用 Nike 的一句话:JUST DO IT。
第二条建议——永远不要依赖别人的界面。始终在每个类的级别上写入您希望存在的接口 - 根据需要为实际实现编写适配器。
此外,我发现避免方法返回值以及从消息传递而不是函数调用的角度考虑代码很有用。
YMMV.
【讨论】:
【参考方案12】:一年前,我对如何进行 TDD 几乎一无所知(但我真的很想(多么令人沮丧))并且从未听说过 BDD ......现在我都强迫性地这样做了。我一直在 .Net 开发环境中,而不是 Java,但我什至用宏替换了“F5 - 运行”按钮来运行 Cucumber (BDD) 或 MBUnit (TDD),具体取决于它是功能/场景还是规范。如果可能的话,没有调试器。如果您使用调试器(开玩笑(有点)),则 jar 中的 $1。
这个过程非常棒。我们另外使用的框架是我有幸遇到的 Oracle,并从中吸收信息,而他/我们使用的框架是 MavenThought。
一切都从 BDD 开始。我们的 BDD 是铁红宝石上的黄瓜。
特点:
场景:.... 鉴于我做废话... 当我做其他事情时... 然后奇妙的事情发生了……
场景:...
这不是单元测试本身,而是逐个场景驱动功能,进而推动单元(测试)规范。因此,您从一个场景开始,并在场景中完成每个步骤驱动您的 TDD。
我们一直在使用的 TDD 在某种程度上是一种 BDD,因为我们着眼于 SUT(被测系统)要求的行为,并且每个规范都指定了一个行为(类“测试”文件)。
例子:
这是一种行为的规范:创建被测系统时。
还有一个规范(C#When_blah_happens 类文件)用于属性更改时的另一种行为,但它被分离到一个单独的文件中。
using MavenThought.Commons.Testing;
using SharpTestsEx;
namespace Price.Displacement.Module.Designer.Tests.Model.Observers
/// <summary>
/// Specification when diffuser observer is created
/// </summary>
[ConstructorSpecification]
public class When_diffuser_observer_is_created
: DiffuserObserverSpecification
/// <summary>
/// Checks the diffuser injection
/// </summary>
[It]
public void Should_return_the_injected_diffuser()
Sut.Diffuser.Should().Be.SameInstanceAs(this.ConcreteDiffuser);
这可能是 SUT 最简单的行为,因为在这种情况下,当它被创建时,Diffuser 属性应该与注入的扩散器相同。我不得不使用 Concrete Diffuser 而不是 Mock,因为在这种情况下,Diffuser 是一个核心/域对象,并且没有接口的属性通知。 95% 的情况下,我们引用所有依赖项,例如 Dep(),而不是注入真实的东西。
通常我们有不止一个 [It] Should_do_xyz(),有时还有一些设置,比如可能多达 10 行存根。这只是一个非常简单的示例,该规范中没有 GivenThat() 或 AndGivenThatAfterCreated()。
对于每个规范的设置,我们通常只需要覆盖规范的几个方法:
GivenThat() ==> 这发生在 SUT 创建之前。
CreatSut() ==> 我们使用 StructureMap 自动模拟创建 sut,并且 90% 的时间不需要覆盖它,但如果您是构造函数注入混凝土,则必须覆盖它。
AndGivenThatAfterCreated() => 这发生在 SUT 创建之后。
WhenIRun() => 除非它是 [ConstructorSpecification],否则我们使用它来运行我们为 SUT 指定的行为的一行代码
此外,如果同一 SUT 的两个或多个规范存在共同行为,我们会将其移至基本规范中。
运行规范我要做的就是突出显示它的名称,例如“When_diffuser_observer_is_created”,然后按 F5,因为请记住,对我来说,F5 运行 Rake 任务,如果 Cucumber 则为 test:feature[tag],或者 test:class[SUT ]。对我来说很有意义,因为每次运行调试器时都会被扔掉,不会创建任何代码(哦,它要花 1 美元(开玩笑))。
这是一种非常非常简洁的方式来指定 TDD 的行为,并且具有非常非常简单的 SUT 和简单的规范。如果您尝试成为牛仔程序员并编写具有硬依赖等的 SUT 蹩脚的东西,您将感到尝试执行 TDD 并厌倦/放弃或咬紧牙关做对的痛苦。
这是实际的 SUT。我们有点花哨,并使用 PostSharp 在扩散器上添加属性通知更改,因此 Post.Cast。再说一次,这就是我注入混凝土而不是模拟的原因。无论如何,正如您所看到的,在另一个规范中定义的缺失行为是当扩散器发生任何变化时。
using System.ComponentModel;
using MavenThought.Commons.Events;
using PostSharp;
using Price.Displacement.Core.Products;
using Price.Displacement.Domain;
namespace Price.Displacement.Desktop.Module.Designer.Model.Observers
/// <summary>
/// Implementation of current observer for the selected product
/// </summary>
public class DiffuserObserver : AbstractNotifyPropertyChanged, IDiffuserObserver
/// <summary>
/// gets the diffuser
/// </summary>
public IDiffuser Diffuser get; private set;
/// <summary>
/// Initialize with a diffuser
/// </summary>
/// <param name="diffuser">The diffuser to observe</param>
public void Initialize(IDiffuser diffuser)
this.Diffuser = diffuser;
this.NotifyInterface().PropertyChanged += (x, e) => this.OnPropertyChanged(e.PropertyName);
/// <summary>
/// Gets the notify interface to use
/// </summary>
/// <returns>The instance of notify property changed interface</returns>
protected INotifyPropertyChanged NotifyInterface()
return Post.Cast<Diffuser, INotifyPropertyChanged>((Diffuser)Diffuser);
总之,这种 BDD / TDD 开发风格令人震撼。花了一年时间,但作为一种生活方式,我完全皈依了。我自己不会学到这一点。我从 The Oracle http://orthocoders.com/ 那里得到了所有东西。
红色或蓝色药丸,由您选择。
【讨论】:
以上是关于饮食、睡眠和呼吸单元测试/TDD/BDD [关闭]的主要内容,如果未能解决你的问题,请参考以下文章