我在编写 API 和核心功能时会编写单元测试。但我想成为一个吃、睡、呼吸 TDD 和 BDD 的酷迷。正确开始使用 TDD/BDD 的最佳方法是什么?有什么书籍、资源、框架、最佳实践吗?

我的环境是 Java 后端和 Grails 前端,与多个外部 Web 服务和数据库集成。

有帮助吗?

解决方案

一个好的起点是阅读博客。然后购买写博客的人的书。我强烈推荐一些:

“鲍勃叔叔”马丁和 Object Mentor 的成员们:http://blog.objectmentor.com/

附:获取鲍勃的书《干净的代码》:

http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882

我的朋友蒂姆·奥廷格(前对象导师)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.triversinstitute.org/blog/?p=29

TDD 的其他“著名”支持者包括:

他们都是值得追随的伟大人物。您还应该考虑参加一些会议,例如 Agile 2010 或 Software Craftsmanship(今年它们在芝加哥同时举行)

其他提示

当人们说<!>时,我不喜欢它;练习X从来都不是坏事;如果它不起作用,你做得不对。<!> quot;对不起,它和其他任何过度热心的宗教教条一样。我不买。

我同意那些说你的时间和金钱能够承受的最佳解决方案的人应该成为目标。

任何反对TDD的人不应自动被指责无视质量。 (<!>;所以你什么时候停止殴打你的妻子?<!>;)事实上,软件中存在漏洞,消除所有漏洞的成本必须权衡利益。

制造业同样如此。表面尺寸和表面处理的公差并不完全相同,因为有时不保证公差和镜面光洁度。

是的,我写单元测试,虽然在我写课之前并不常见。我已经看到了测试对设计的影响。我测量并观察代码覆盖率。如果我发现我的报道不可接受,我会写更多的测试。我理解单元测试安全网对重构的好处。即使我独自工作,我也会遵循这些做法,因为我亲身体验了这些好处。我明白了。

但我会对任何一个开始讨厌<!>“吃饭,睡觉,呼吸单位测试和TDD的队友表示怀疑。<!>

  

我的经理说,促使我升职的唯一方法就是让团队加入TDD / BDD。

有没有想过这可能会让你听起来像个傻瓜?您是否发现您的唠叨已经疏远了团队的其他成员?

这种回应可能会让我失去一些声望点,但不得不说。

我认为更好的方法是自己练习,让别人看到好处。以身作则。它比用嘴巴更有说服力。

Geez,Grails内置测试代。如果您正在使用使用Grails的团队,那么还需要多少销售?

最佳实践恕我直言:做什么是实用的,而不仅仅是因为它是一个过程。不要忘记编写应用程序的目标是什么,而在商业世界中,它不是编写测试。不要误会我的意思,他们有自己的位置,但这不应该是目标。

找到一直在做TDD / BDD的人并与他们配对。

衡量标准是,恕我直言,从这里到那里的最佳方式。跟踪代码的覆盖程度,为每次提交保留代码复杂度的增量,使用监视代码进行更改的测试运行者,并不断重新运行相应的测试。永远不要让测试长度超过几行,以便您的所有工具都能正常工作。我建议每月一次,休息一天,通过变异测试仪运行你的代码。那天应该专注于编写测试。如果你还没有做好TDD,所有这些东西都会给你带来痛苦。从疼痛中学习,并且在任何时候,你都会做得很好。

永远不要忘记测试的用途:描述所需的行为。它们是您的可执行规范。 (这也是我喜欢黄瓜的原因;现在你可以让你的PHB为你写测试!好吧,也许不是非常好,但它很接近!)

<!> PS:我的经理说,促使我升职的唯一方法就是让团队参加TDD / BDD。<!>

让团队做某事的唯一现实方法(在此过程中不会杀死你)是向他们清楚地证明,改变他们的习惯会使他们受益。换句话说,写代码。很多代码。大量的代码。然后,当关键电子邮件到达时会彻底改变规范,向他们表明您可以通过重构轻松更改代码,并且因为您已经准备并且测试已经准备就绪了。酒吧是绿色的,hack hack hack,RED BAR !!!!,hack hack hack,green bar,回家。

阅读Kent Becks关于测试驱动设计的书。从测试开始,然后执行代码。获取运行RUNS THE TESTS的构建服务器!你不需要为整个团队拥有它 - 为自己做,并向他们展示它有帮助。

讲道只会惹恼当地人:)

我从事 TDD 已经有几年了,但最近我开始更多地研究 BDD 方式来驱动我的设计和开发。帮助我开始使用 BDD 的资源首先是 Dan North 的博客(BDD 的“创始人”)。看一眼 介绍 BDD. 。还有一个“官方”BDD Wiki,位于 行为驱动网站 有一些值得一读的好帖子。

当我开始使用 BDD 时,我发现真正困难的一件事(并且仍然觉得有点困难)是如何制定这些场景以使其适合 BDD。Scott Bellware 是一位精通 BDD(或者他喜欢创造的 Context-Spesification)和他的文章的人 行为驱动开发 《Code Magazine》对我理解 BDD 思维方式和制定用户故事有很大帮助。

我还推荐 TekPub 截屏视频 使用 Specflow 进行行为驱动设计 作者:罗布·康纳利。对 BDD 和非常适合在 C# 中执行 BDD 的工具 (SpecFlow) 的精彩介绍。

至于TDD资源,这里已经有很多很好的推荐了。但我只想指出几本我真正可以推荐的书;

开始进行单元测试,然后阅读有关如何做到最后教你的团队如何进行TDD并让他们参与进来的原因 - 因为根据我的经验,没有什么比与整个团队进行单元测试更重要了。

您还需要一个正确的构建过程 - 使用构建服务器来构建代码并运行测试我建议使用TeamCity(免费限制)。

学习如何正确进行良好的单元测试是困难的部分 - 你可以自己学习一些(只要你保持单元测试),其余的你可以通过搜索互联网来学习。

当你不编写单元测试时,你会知道你达到了目标,因为开发的一部分会让你看错。

请记住,敏捷意味着您没有完全以任何特定方法销售一空。如果您正在处理TDD的好处不值得的事情(比如在Swing界面上进行试错编辑),那么请不要使用TDD。

我看不出有人真正表达过 TDD 是 不是 关于测试。TDD-ing 是在进行微小的行为改变修改之前表达预期的行为。这极大地改进了设计,并能够以我以前从未体验过的方式集中注意力。您可以免费获得可保护您未来重构的测试和 90% 的覆盖率。

为了学习它,我建议(总结其他人所说的并添加我自己的之一):

  1. 访问博客并阅读上述书籍
  2. 与精通 TDD 的人结对
  3. 实践

在我开始看到曙光之前,我自己练习了大约 20 次保龄球型(练习)(每次大约 30 分钟)。首先分析鲍勃叔叔的描述 这里. 。codingdojo.org 网站上有大量 katas,包括解决方案和讨论。尝试一下!

引用耐克的话:只做它。

第二条建议 - 永远不要依赖别人的界面。始终在每个类的级别上写入您希望存在的接口 - 根据需要为实际实现编写适配器。

另外,我发现避免在方法上返回值,并根据消息传递而不是函数调用来考虑代码是有用的。

因人而异。

一年前,我不知道如何做TDD(但真的很想(多么令人沮丧))并且从未听说过BDD ...现在我强制要求。我一直在.Net开发环境中,而不是Java,但我甚至更换了<!>“F5 - Run <!>”;具有宏的按钮可以运行Cucumber(BDD)或MBUnit(TDD),具体取决于它是功能/场景还是规范。如果可能的话,没有调试器。如果您使用调试器(JOKING(排序)),jar中$ 1。

这个过程非常棒。我们另外使用的框架是Oracle,我很幸运能够接触到这些框架,从中吸收信息,他/我们使用的框架是MavenThought。

一切都从BDD开始。我们的BDD是铁红宝石上直立的黄瓜。

特点:

情景:....    鉴于我做了... ...    当我做别的事情......    然后奇妙的事情发生......

场景:......

这不是单元测试本身,但它驱动功能,逐个场景,反过来单元(测试)规范..所以你开始一个场景,并在每个步骤,你需要在场景中完成它推动你的TDD。

我们一直使用的TDD在某种程度上是一种BDD,因为我们查看SUT(系统测试)所需的行为,并且每个规范指定一个行为(class <!> quot; test <!> “;文件)。

示例:

以下是一种行为的规范:创建受测试系统时。

当属性发生更改时,还有一个规范(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属性应该与注入的漫射器相同。我不得不使用混凝土扩散器而不是Mock,因为在这种情况下,扩散器是Core / Domain对象,并且没有接口的属性通知。 95%的时间我们引用所有依赖项,如Dep(),而不是注入真实的东西。

通常我们有多个[It] Should_do_xyz(),有时甚至可能有多达10行的存根。这只是一个非常简单的例子,在该规范中没有GivenThat()或AndGivenThatAfterCreated()。

对于每个规范的设置,我们通常只需要覆盖规范的几个方法:

GivenThat()== <!> gt;这是在创建SUT之前发生的。

CreatSut()== <!> gt;我们使用StructureMap自动模拟sut的创建,90%的时间永远不需要覆盖它,但如果你是构造函数注入一个Concrete,你必须覆盖它。

AndGivenThatAfterCreated()= <!> gt;这是在创建SUT之后发生的。

WhenIRun()= <!> gt;除非它是[ConstructorSpecification],否则我们使用它来运行一行代码,这是我们为SUT指定的行为

此外,如果同一SUT的两个或多个规范存在共同行为,我们将其移至基本规范中。

我需要做的就是运行规范,突出显示它的名称,例如<!>“When_diffuser_observer_is_created <!> quot;然后按F5,因为记住,对我来说,F5运行一个Rake任务要么测试:feature [tag] if Cucumber,或者test:class [SUT]。对我来说很有意义,因为每次运行调试器都会丢掉它,没有代码被创建(哦,花费1美元(开玩笑))。

这是一种非常非常干净的方式,用TDD指定行为,并且具有非常简单的SUT和简单的规范。如果你试着成为牛仔编码器,并写出SUT蹩脚的硬依赖等等,你会感到尝试做TDD并厌倦/放弃或咬紧牙关并做正确的痛苦。

这是实际的SUT。我们有点花哨,并使用PostSharp在Dif上添加属性通知更改fuser,因此Post.Cast <!> lt; <!> gt;。再次,这就是我注入混凝土而不是模拟的原因。无论如何,正如您所看到的那样,另一个规范中定义的缺失行为是在扩散器上发生任何变化时。

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的发展方式岌岌可危。花了一年的时间,但我是一个完全皈依的生活方式。我不会靠自己学到这一点。我从Oracle http://orthocoders.com/ 中获取了所有内容。

红色或蓝色药丸,选择权在您手中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top