我刚刚进入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,为什么我不应该?这里似乎仍然有一些模糊的线条,我觉得我不太了解。
答案 0 :(得分:29)
一个非常重要提出的观点是两种风格的行为驱动开发。这两种风格是 xBehave 和 xSpec 即可。
SpecFlow(非常类似于Ruby堆栈中的cucumber)非常适合将xBehave BDD测试作为验收标准。然而,它并没有提供在单元级别编写行为测试的好方法。还有一些其他xBehave测试框架,但SpecFlow已经获得了很大的吸引力。
对于单元级别的行为驱动开发,我建议NSpec(直接受RSpec启发,感谢Ruby)。您可以通过简单地使用NUnit或MSTest来完成单元级别的BDD ...但它们有点不足(很难逐步建立上下文)。 MSpec也是一个选项,已经做了很多工作,但是在NSpec中只有一些简单的东西(你可以在MSpec中逐步建立上下文,但它需要继承,这可能会变得复杂)。
两种口味的BDD主要存在,因为它们提供了正交的好处。
Bowling Kata是一个很好的例子。
这是规范在SpecFlow中的样子(再次,这是一个很好的验收测试,因为它直接与业务沟通):
特征文件要素文件是测试的常用方言。
Feature: Score Calculation In order to know my performance As a player I want the system to calculate my total score Scenario: Gutter game Given a new bowling game When all of my balls are landing in the gutter Then my total score should be 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);
}
}
这是同一个保龄球kata的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);
}
}
当你做越来越多的BDD时,你会发现需要BDD的xBehave和xSpec风格。 xBehave更适合验收测试,xSpec更适合单元测试和域驱动设计。
答案 1 :(得分:11)
真正的行为驱动工具就像Cucumber。我们在针对.NET代码的工作中使用它。这允许我们编写定义系统整体行为的功能,然后我们可以执行这些功能并验证系统是否符合我们的预期。整个过程对我们来说非常有效。
有一个名为NStep的.net实现,它通过有线协议连接到黄瓜,它允许你使用lambdas在C#中编写步骤定义...它非常棒。
步骤定义如下所示:
When("^I go to the \"([^\"]*)\" (?:[Ss]creen|[Pp]age)$", (string pageName) =>
{
var screen = ParseScreen(pageName);
GoToScreen(screen);
World.Browser.Wait(1000);
});
答案 2 :(得分: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.
没有理由不在更细粒度级别对您的存储库进行单元测试。我认为两者都是有用和适当的。
答案 3 :(得分:2)
我不能只使用普通的单元测试工具吗? BDD是一个过程和心态,所以,是的,您可以使用任何工具(或者不是,如果您愿意,您可以在没有工具的情况下编写自己的工具)。然而,TDD工具有某些假设,当试图以BDD方式做事时会引起一些摩擦。例如,TDD假设您正在测试该软件的架构单元;班级,模块,服务。而BDD假设您正在指定系统的某些功能部分。
我应该使用SpecFlow / Cucumber来描述较低级别的组件吗? 首先,我认为这个问题有点误导。除非这些组件直接表示行为,否则您不会倾向于描述组件。我仍然会回答我相信问题的精神。
像Cucumber这样的面向故事的工具非常适合从客户/用户角度谈论行为。它可以让您制作出非常容易接近的规格。但是,使用这些工具描述大量或复杂的状态可能会很繁琐。
在处理复杂或大型状态设置时,单元测试或更多面向代码的规范工具(如rSpec和Machine.Specification)可以更方便。您可以使用语言可用的各种工具来管理状态。继承和假货/嘲笑之类的东西。 Machine.Specification为.NET思想提供了一些很好的方法。
那么,您是否应该使用Cucumber来指定较低级别的行为?我只会说,对于特定行为具有高度可见性非常重要。在我目前的项目中,我们开发了一个架构组件来表示系统中某些业务规则密集型部分。这些组件使用Cucumber指定,但大多数系统都包含NUnit。
顺便说一句,对于刚刚进入BDD的.NET人来说,SpecFlow真的很好用,也很平易近人,但最终你会想要毕业于成熟的Cucumber + nStep。黄瓜生态系统是巨大而有益的。 SpecFlow的尺寸要小得多。
此外,nStep提供的lambda语法比装饰SpecFlow或Cuke4Nuke的方法要好得多。
声明/背景: 我在nStep上做了一些原始的开发,但我在我当前的项目中使用了SpecFlow。我正在努力在这里介绍BDD,需要一些简单易用的东西。
答案 4 :(得分:0)
有趣的是,这篇关于BDD工具分类的博客讨论了TDD和ATDD。正如Liz Keogh指出:BDD is about conversation and exploration。所有参与者都更容易做出贡献,沟通意见,分享想法,了解其他人等等,我们能够更快地获得适当的解决方案以及我们构建的更好的软件。当我们最终遵循工具路径时,哪些工具最能支持软件项目利益相关者之间的协作?
基于this blog on the differences between TDD, BDD, and ATDD我会说至少有三种不同风格的BDD 工具:
JUnit改变了我们对开发和测试的看法。它的优势之一是测试可以用与应用程序本身相同的编程语言编写。因此,我们可以利用我们在交付团队中已有的知识。当测试甚至用于推动开发时,我们就达到了TDD的天堂。
编程语言已经过优化以减少冗余,这是Ron Jeffries认为开发人员最严重的罪行之一。因此,当我们进行技术测试以正确构建产品时,我们通常会依赖这些工具,因为它们可以帮助我们提高效率。
有些人尝试使自动化测试更容易理解,如unit tests aren't really readable。最初的尝试之一是解析单元测试并提供非开发人员可读的简明摘要。例如,TestDox / AgileDox根据JUnit测试类的方法名称创建简单文档,或Pickels根据Gherkin编写的功能文件生成文档。
MSpec等框架有助于编写更易读的测试,并提供可读输出。这些BDD工具的注重力集中在人类可读的输出上,这使得非开发人员能够在开发人员完成工作后参与其中。
到involve stakeholders earlier in the development cycle,创建了更多关注可读输入的新工具。 Cucumber利用纯文本文件为自动化测试提供人类可读的输入。文本文件包含基于给定时间结构以特殊结构语言编写的场景。这些框架是支持协作定义验收标准的很好的工具。
与BDD理念并行,已经开发出另一种工具,其中FIT是早期的代表。此Framework for Integrated Test允许在表中指定嵌入到与示例相关的文档中的示例。要编写这些文档,不需要开发技能,非技术人员可以轻松阅读和审阅这些文档,因为它们纯粹是基于文本的。此外,文本可以结构化,因为文档不是纯文本文件,而是丰富编辑器的输出。
FitNesse允许基于Wiki协作指定预期行为。由于wiki易于访问和使用,因此入门和学习曲线较低,这推动了整个团队的共同工作。许多敏捷支持者强调,合作的最佳方式是面对面交流。但是,如果你写下你所思考和讨论的内容,它应该尽可能丰富和结构良好。
Concordion提供了很大的灵活性,因为您可以使用段落,表格和正确的标点来用正常语言描述您的要求。描述的任何部分都可以用作自动测试的输入和被测系统输出的验证。由于它基于HTML,您可以构建文档并集成图像。简单地说,您有网络的表现力来描述预期的行为。
您可以使用所有三种工具实现BDD,但每种工具都有其优点和缺点。单元测试框架和类似xSpec的工具完美地利用了编程的优势。因为它们是来自开发人员的工具 ,如果你试图使技术部分正确,它们是一个完美的选择。
当您想要传达应用程序的意图时,您最好使用与编辑器用于工作的工具密切相关的工具。如果规范仅包含输入和预期输出,则读取它的任何人都必须根据输入与预期输出的关系重构您的想法。解释标题中规范目标的简短描述有助于读者理解规范的结构。基于规范的文档可能如下所示:
是的,SpecFlow很酷,NSpec很酷......
FitNesse和Concordion也很酷