ATDD与BDD的区别以及框架的正确使用

21
我刚开始了解BDD的概念,并听了Scott Bellware与Herding Code小组的谈话。我一直在玩SpecFlow并且很喜欢它。
我理解Classifying BDD Tools (Unit-Test-Driven vs. Acceptance Test Driven) and a bit of BDD history博客文章中所描述的ATDD和TDD的区别,但这引出了一个问题。
如所述,使用BDD工具(如MSpec)难道不就是另一种单元测试框架吗?对我来说似乎是这样。
此外,这似乎表明使用SpecFlow规范低级组件(如存储库和服务)是错误的。如果我可以同时用于低级组件的ATDD和TDD使用相同的工具,为什么不应该呢?我感觉这里仍然有一些模糊的界限,我还没有完全理解。
5个回答

30

简短回答

需要提醒的一点是,行为驱动开发有两种类型。这两种类型分别是xBehavexSpec

xBehave BDD: SpecFlow

SpecFlow(类似于 Ruby 中的 cucumber)非常适合作为验收标准来促进 xBehave BDD 测试。但是,它并不提供一种很好的方法来编写单元级别的行为测试。还有一些其他的 xBehave 测试框架,但 SpecFlow 已经得到了广泛的应用。

xSpec BDD: NSpec

对于单元级别的行为驱动开发,我建议使用 NSpec(直接受到 Ruby 的 RSpec 启发)。您可以通过简单地使用 NUnit 或 MSTest 实现单元级别的 BDD……但它们有点不足(在逐步构建上下文方面非常困难)。MSpec 也是一个选择,已经投入了大量的工作,但在 NSpec 中有一些事情更加简单(您可以在 MSpec 中逐步构建上下文,但这需要继承,可能会变得复杂)。

详细回答

BDD有两种主要的风格,主要是因为它们提供了正交的好处。

xBehave(GWT语法)的优缺点

优点

  • 通过一个称为“通用方言”的共同语言,帮助促进与业务的交流(例如,Given ....,And Given ....,When ......,And When .....,Then ....,And Then)
  • 通用方言可以映射到可执行代码,证明您实际完成了承诺的工作
  • 该方言是约束性的,所以业务必须消除要求的歧义,并使其符合句子。

缺点

  • 虽然xBehave方法适用于驱动高级验收标准,但通过属性将英语映射到可执行代码所需的周期使其不适用于在单元级别确定域。
  • 将通用方言映射到测试是痛苦的(加强您的正则表达式)。业务创建的每个句子都必须通过属性映射到可执行方法。
  • 必须严格控制通用方言,以便管理映射不会失控。每次更改一个句子时,都必须找到直接与该句子相关的方法并修复正则表达式匹配。

xSpec(上下文/规范)的优缺点

优点

  • 允许开发人员逐步构建上下文。可以为测试设置上下文并对该上下文执行某些断言。然后可以指定更多的上下文(在已有的上下文基础上构建),然后指定更多的测试。
  • 没有约束性语言。开发人员可以更加表达系统的某个部分的行为。
  • 不需要英语和通用方言之间的映射(因为不存在这样的方言)。

缺点

  • 业务人员不太容易接受。面对现实吧,业务人员不喜欢澄清他们想要什么。如果我们给他们一种基于上下文的BDD方法,那么这个句子就只会是“让它工作”。
  • 所有内容都在代码中。上下文文档与代码交织在一起(这就是为什么我们不必担心将英语映射到代码中)。
  • 使用较少限制性措辞时不太可读。

示例

保龄球Kata是一个相当好的例子。

SpecFlow示例

以下是在SpecFlow中规格说明的样子(再次强调,作为验收测试非常棒,因为它直接与业务沟通):

功能文件是测试的通用方言。

Feature: Score Calculation 为了了解我的表现 作为一名玩家 我希望系统计算我的总得分
Scenario: Gutter game 假如有一个新的保龄球游戏 当所有球都落在沟里时 那么我的总得分应该是0

步骤定义文件是测试的实际执行,该文件包括SpecFlow的映射


[Binding]
public class BowlingSteps
{
    private Game _game;
[Given(@"a new bowling game")] public void GivenANewBowlingGame() { _game = new Game(); }
[When(@"all of my balls are landing in the gutter")] public void WhenAllOfMyBallsAreLandingInTheGutter() { _game.Frames = "00000000000000000000"; }
[Then(@"my total score should be (\d+)")] public void ThenMyTotalScoreShouldBe(int score) { Assert.AreEqual(0, _game.Score); } }

NSpec示例,xSpec,上下文/规范

这里是相同保龄球卡塔的NSpec示例:


class describe_BowlingGame : nspec
{
    Game game;
void before_each() { game = new Game(); }
void when_all_my_balls_land_in_the_gutter() { before = () => { game.Frames = "00000000000000000000"; };
it["should have a score of 0"] = () => game.Score.should_be(0); } }

所以,SpecFlow很酷,NSpec也很酷

随着您越来越多地使用BDD,您会发现xBehave和xSpec两种BDD都是必需的。xBehave更适合验收测试,xSpec更适合单元测试和领域驱动设计。

相关链接


11
一个真正的行为驱动工具应该类似于Cucumber。我们在我的工作中使用它来针对.NET代码进行测试。这使我们能够编写定义系统整体行为的功能,然后执行这些功能并验证系统是否按照我们的期望运行。整个过程对我们非常有效。

http://cukes.info/

有一个名为NStep的.NET实现,通过wire协议连接到cucumber,它允许您使用lambda在C#中编写步骤定义...非常棒。
步骤定义看起来像这样:
When("^I go to the \"([^\"]*)\" (?:[Ss]creen|[Pp]age)$", (string pageName) =>
{
    var screen = ParseScreen(pageName);
    GoToScreen(screen);
    World.Browser.Wait(1000);
});

http://github.com/clearwavebuild/nStep


1
SpecFlow是Cucumber的.NET实现。 - Brian McCord
除非它是一个克隆版本,具有自己的解析器并将步骤编译为单元测试。无论多么好,克隆品都不会像原版那样好。Cucumber不断添加功能,使BDD方法成为编写软件的绝佳方式。你应该去了解一下实际的Cucumber...它非常强大。 - Chris Kooken
BDD工具真正的设计目的是测试行为。因此,它应该涵盖整个系统。对于底层核心业务流程,如存储库,我会使用NUnit,使用SpecFlow或Cucumber进行行为测试。 - Chris Kooken
这就是为什么我喜欢 Stack Overflow,每天都能学到新东西。SpecFlow 和 Cucumber 看起来非常酷。 - Nathan W
3
支持使用NStep而不是重复造轮子。NStep实现了黄瓜Wire协议,因此您可以在.NET中实现步骤,同时使用Ruby的黄瓜运行器。SpecFlow也很好,但您会错过所有适用于黄瓜的工具。您也无法混合使用简单和动态的Ruby代码(适用于与Selenium等API一起使用),以及.NET代码(适用于与数据库和服务接口一起使用)。 - Joseph Daigle
2
SpecFlow目前使用的是官方Gherkin解析器,该解析器也用于Cucumber。在工具方面,SpecFlow致力于为标准的.NET开发环境提供良好的体验。VisualStudio的集成不断改进,并且使用现有的测试自动化框架(NUnit,MSTest等)来执行是为了无缝集成到现有基础设施中的明确决策。我们努力避免重复造轮子... - jbandi

2

我认为您的理解与我的一致。BDD更适用于集成测试,通常会测试您的系统作为最终用户的使用情况,例如:

Given I am an authorised user
When I go to the front page
Then there should be a link to my profile with my username as the link text.

没有理由不在更细粒度的层面上对存储库进行单元测试。我认为两者都是有用和适当的。


我仍然使用NUnit测试我的存储库、服务等,但我真正想知道的是,是否将SpecFlow用于此目的被认为是“错误”的。 - Brian McCord
2
我认为是这样,SpecFlow更适合测试大块的代码,而不需要模拟或隔离。 - Igor Zevaka
我同意Igor的观点,因为使用BDD工具的真正优势在于它允许业务用户编写测试(或者说,它允许业务用户理解测试)。由于业务只关心整个系统,因此BDD工具适合测试整个系统。如果存储库不能与整个系统集成,业务实际上并不关心它是否有效。因此,对于更多的单元级测试,BDD可能会阻碍而不是帮助。 - Sir Rippov the Maple

2

我可以使用普通的单元测试工具吗? BDD是一种过程和心态,所以,是的,您可以使用任何工具来完成它(或者不使用工具,如果您想自己编写)。但是,TDD工具有一些假设,当试图以BDD方式执行操作时,会导致一些摩擦。例如,TDD假设您正在测试软件的架构单元;类、模块、服务。而BDD假设您正在指定系统的某个功能部分。

我应该使用SpecFlow/Cucumber来描述低级组件吗? 首先,我认为这个问题有点误导人。除非那些组件直接代表行为,否则您不会倾向于描述组件。我仍然会回答我认为问题精神的内容。

像Cucumber这样的故事导向工具非常适合从客户/用户的角度谈论行为。它可以让您制定易于门外汉理解的规范。但是,使用这些工具描述大量或复杂状态可能会很繁琐。

单元测试,或更多面向代码的规范工具,如rSpec和Machine.Specification,在处理复杂或大型状态设置时可以更加方便。您可以使用语言提供的各种工具来管理状态。例如继承和伪造/模拟。Machine.Specification 对于.NET方面有一些不错的方法。

那么,您应该使用Cucumber来指定低级别行为吗?我会说只有在对该特定行为具有高度可见性很重要时才使用。在我的当前项目中,我们开发了一个架构组件,用于表示系统的某些业务规则密集部分。这些组件使用Cucumber进行规定,但是大部分系统都使用NUnit进行覆盖。


顺便说一句,SpecFlow非常适合.NET新手入门BDD,但最终您会想要升级到完整的Cucumber+nStep。Cucumber生态系统非常庞大且有帮助。nStep提供的lambda语法比必须像SpecFlow或Cuke4Nuke那样装饰方法要好得多。

免责声明/背景: 我曾经参与过nStep的原始开发,但是我目前在我的项目中使用SpecFlow。我正在努力引入BDD,并需要一些简单易懂的东西。


0

有趣的是,这篇关于分类BDD工具的博客谈到了TDD和ATDD。正如Liz Keogh所指出的那样:BDD是关于对话和探索的。所有参与者都能够贡献、沟通意图、分享想法、理解其他人等等,我们就能更快地得到一个合适的解决方案,并构建更好的软件。当我们最终遵循工具路径时,哪些工具最好支持软件项目利益相关者之间的协作呢?

基于这篇关于TDD、BDD和ATDD差异的博客,我认为至少有三种不同风格的BDD工具

  1. 单元测试框架

JUnit改变了我们对开发和测试的看法。它的一个优点是测试可以用与应用程序本身相同的编程语言编写。因此,我们可以在交付团队已经拥有的知识基础上进行构建。当测试甚至被用来驱动开发时,我们就达到了TDD的天堂。

编程语言已经被优化以减少冗余,这是根据Ron Jeffries的说法开发人员最糟糕的罪恶之一。因此,在进行技术测试时,我们通常依赖于这些工具来正确构建产品,因为它们帮助我们最有效率。

一些人试图使自动化测试更易于理解,因为单元测试并不真正可读。其中一个最早的尝试是解析单元测试并提供简洁的摘要,也适合非开发人员阅读。例如TestDox / AgileDox从JUnit测试类的方法名称创建简单的文档,或者Pickels基于用Gherkin编写的功能文件生成文档。

MSpec这样的框架有助于编写更易于阅读的测试,并提供易于阅读的输出。这种BDD工具的风格专注于人类可读的输出,这使得在开发人员完成工作后可以涉及非开发人员。

  1. 场景测试框架

为了更早地让利益相关者参与到开发周期中, 新的工具被创建出来,这些工具更加注重可读性。Cucumber 使用纯文本文件提供人类可以阅读的输入,以进行自动化测试。这些文本文件包含一种特别结构化语言编写的场景,该语言基于给定-当-那种结构。这些框架是支持共同定义验收标准的绝佳工具。

  1. 验收测试框架

在BDD思想的同时,另一种工具也得到了发展,其中FIT是早期的代表之一。这个集成测试框架允许在嵌入到与示例相关的文档中的表格中指定示例。编写这些文档不需要开发技能,它们可以轻松地被非技术人员阅读和审查,因为它们是纯文本文件。此外,文本可以被结构化,因为这些文档不是纯文本文件,而是富文本编辑器的输出。

FitNesse 允许基于 Wiki 协作指定预期行为。由于 Wiki 易于访问和使用,因此具有低门槛和学习曲线,这推动了整个团队的共同工作。许多敏捷支持者强调协作的最佳方式是面对面交流。但是,如果您写下您所思考和讨论的内容,它应该尽可能丰富和结构良好。

Concordion 提供了很大的灵活性,因为您可以使用段落、表格和适当的标点符号用普通语言描述您的要求。您描述的任何部分都可以用作自动化测试的输入,并用于测试系统输出的验证。由于它基于 HTML,您可以结构化您的文档并集成图像。简单地说,您拥有描述预期行为的 Web 表达能力。

BDD 应该帮助构建正确的产品

您可以使用所有三种工具的 BDD 实现,但每种工具都有其优点和缺点。单元测试框架和 xSpec 类似的工具完美地利用了编程的优势。由于它们是开发人员为开发人员提供的工具,因此如果您试图使技术部分正确,则是一个完美的选择。

当您想要传达应用程序的意图时,最好使用与编辑器工具密切相关的工具。如果规范仅包含输入和预期输出,则任何阅读它的人都必须从输入与预期输出的关系中重构您的想法。在标题中解释规范目标的简短描述有助于读者理解规范的结构。基于示例规范的文档可能如下所示:

enter image description here enter image description here

是的,SpecFlow很酷,NSpec也很酷...

FitNesse和Concordion也很酷


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接