使用BDD时如何使用单元测试?


17

我试图了解BDD。我读过一些文章,据我了解,BDD是TDD的“下一步”。我之所以这么说是因为我发现两者非常相似,并且正如我在本文中所读到的那样,BDD是TDD的改进。太好了,我真的很喜欢这个主意。

我没有想到一个实用的观点:有一个.feature文件,BA将在其中写入系统将具有的所有预期行为。作为一名学士学位,他不知道系统的构建方式,因此我们将编写如下内容:

+方案1:帐户已入帐+

鉴于该帐户已贷记

而且卡是有效的

而且分配器中有现金

当客户要求现金时

然后确保帐户已借记并确保已分配现金

并确保卡已归还

好的,这很不错,但是系统中的许多部分都可以进行协作,以便可以实现(例如Account obj,Dispenser obj,Customer obj等)。在我看来,这就像一个集成测试。

我想进行单元测试。我如何测试检查分配器是否有钱的代码?还是分配了现金?还是该帐户在需要时借记? 如何将单元测试与“ BA创建”测试混合?


这就是模拟和存根的用途:隔离测试中的部件。
罗伯特·哈维

对不起,我不明白。你是说我应该嘲笑饮水机?我将如何测试?
JSBach 2015年

测试分配器时,您可以模拟帐户,卡和客户。
罗伯特·哈维

3
为什么要混合单元测试和“ BA创建的测试”?使用TDD作为一种技术来为软件的各个部分创建单元测试,并从BA的角度添加其他测试来测试需求(如果需要,可以调用后者的集成测试)。您在哪里看到矛盾?
布朗

@DocBrown:“自然出现”,我的意思是,一些TDD'ers相信,当您“红绿重构”时,软件设计会自然地从单元测试中出现。关于此问题的正在进行的聊天对话在白板中进行
罗伯特·哈维

Answers:


28

行为驱动开发和测试驱动开发是互补的,但不能相互替代。

验收测试中描述了应用程序的“行为”方式,根据BDD,这将是用Cucumber编写的功能和方案。

单元测试中描述了每个小组件如何工作的细节。单元测试的结果支持您在Cucumber中编写的方案。

想象一下制造汽车的过程。

首先,产品团队提出他们的想法,最后将其归结为使用场景:

Scenario: Starting the car
    Given I am standing in front of the drivers door
    When I open the door
    Then the door should lift up DeLorean-style (yeah, baby!)
    When I get into the car
    And turn the key
    Then the engine roars to life

我知道这种情况听起来有些愚蠢,但这是一个非常高的水平,针对产品和最终用户的需求。仅仅打开车门,转动钥匙并启动发动机就需要很多不同的组件协同工作。这项测试不足以确保车辆正常工作。您需要测试启动器,电池,交流发电机,钥匙,点火开关---并且清单不胜枚举---只是要上车并启动它。这些组件中的每一个都需要自己的测试。

上面的方案是“大图”测试。车辆的每个组件都需要“小图片”测试,以确保它们在整体上正常运行。

在许多方面,构建和测试软件都是相同的。您可以从上至下进行设计,然后从下至上进行构建。如果您什至无法启动发动机,为什么还要提起一扇门?如果没有电池,为什么还要有起动器?

您的产品团队将提出验收测试并将其充实到黄瓜中。这给您“大局”。现在由工程团队来设计适当的组件,以及它们如何交互,然后分别测试每个组件,这就是您的单元测试。

一旦单元测试通过,就开始实施黄瓜方案。一旦这些通过,您就交付了产品团队的要求。


有没有办法将那些“大图片”测试与“小图片”测试联系起来?我的意思是,当功能正式更改时(例如黄瓜场景发生变化),是否有办法将更改映射到低端测试(例如针对特定黄瓜场景的junit测试)?
Srikanth 2015年

您可以在“大图”测试和“小图”测试之间共享帮助程序方法和自定义断言,但是它们很可能涉及不同的设置以测试特定的代码单元。
Nick McCurdy 2015年

[...]根据BDD,这将是用Cucumber编写的功能和场景。您正在混淆原理和工具。
jub0bs 16-4-28

好吧,好的措辞有点差,但是重点是在功能和场景中捕获了应用程序的行为。
Greg Burghardt

9

我试图了解BDD。我已经阅读了一些文章,据我了解,BDD是TDD的“下一步”。我之所以这样说是因为我发现两者非常相似,并且正如我在本文中所读到的那样,BDD是TDD的改进。

实际上,不,BDD 不是 TDD的“下一步”。这 TDD。更确切地说,这是对TDD的重新定义。

BDD的创建者注意到,了解TDD并不是关于测试而是关于行为规范的主要障碍是,所有TDD术语都是关于测试而不是行为规范。这就像有人在对您说“不去想粉红色的大象”时不去想粉红色的大象一样,除了在充满粉红色大象的房间和一个不断大喊“粉红色的大象,粉红色的大象”的情况下增加了复杂性。大象,粉红色的大象”在你的耳朵。

因此,他们在行为规范方面改写了TDD。“测试”和“测试用例”现在是“示例”,“单元”是“行为”,“断言”是“期望”,依此类推。

但是,方法仍然相同。您从接受测试(我的意思是“功能”)开始,放大到单元测试(我的意思是“示例”),再缩小等。

我想进行单元测试。我如何测试检查分配器是否有钱的代码?还是分配了现金?还是该帐户在需要时借记? 如何将单元测试与“ BA创建”测试混合?

您在TDD中的处理方式相同。您可以使用不同的框架(例如Cucumber和RSpec)或什至不同的语言(例如,用C编写C项目的示例,以及使用FIT / Fitnesse编写功能)来编写功能和示例,可以为这两者使用单个功能框架(例如,用Cucumber编写示例和功能),或者您都可以使用单个示例框架(例如,用RSpec编写)。您甚至根本不需要使用框架。

仅使用一个框架的TDD-done-right(与BDD相同)的一个示例是JUnit本身,其中包含单元测试(示例)和功能/集成测试(功能)的混合,所有这些都是用JUnit本身编写的。

我相信肯特·贝克(Kent Beck)称其为“迅速发展”。从高层次开始,然后“放大”详细信息,然后再次退出。


1

免责声明:我不是BDD方面的专家,但是我尝试向您介绍您链接到的文章的观点。

TDD是一种实现技术-首先编写一个测试,然后实现该方法,然后运行测试,重构并为同一方法或新方法添加更多测试。TDD实际上没有定义任何规则来选择类或方法名称,这取决于您。TDD也不会告诉您“何时完成”。

因此,每当为新方法编写测试时,都必须选择一种方法名称-这就是BDD的意义所在。通过使用上述方案中的业务术语来选择方法名称,并通过描述方式选择它们您的班级行为,您正在执行BDD。每当您问自己“我是否必须添加进一步的测试”时,您都可以查看BA给出的方案,并检查是否已完全实现了它们所需的所有部分。如果没有,您将需要添加更多测试。

本文的作者还建议在选择测试名称时使用与行为有关的命名方案,这就是为什么他建议使用一种不依赖于命名方案的工具来代替JUnit的方式,每个测试用例必须以名称为“测试”。尽管我不了解JBehave,但我认为那是该工具与Junit之间的主要区别。

此外,BDD方案也将成为集成测试的蓝图-通常,在通过TDD充实方法名称并添加合理数量的单元测试之后,通常会添加该蓝图。

因此,据我了解,TDD是可以用作BDD一部分的工具,而BDD可以帮助您编写正确的测试并为它们命名。


很快,Junit支持为测试命名。您只需要使用@Test批注。不过,它早在2003年就还没有做过。
soru

@soru早在2003年,它确实实施了“测试”一词。
鲁尼沃尔2015年

本文的作者是Dan North,他首先提出了这个概念。他注意到的一件事是,“测试”一词使我们转向测试实现(解决方案领域),而实际上,探索和定义测试应该确实使我们处于问题领域。Dan将BDD描述为“ TDD的意图”。请阅读以下详细信息:dannorth.net/2012/05/31/bdd-is-like-tdd-if
Lunivore 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.