`
yangzb
  • 浏览: 3502574 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用 easyb 驱动开发

    博客分类:
  • QC
阅读更多

长期以来,定义需求的利益相关者与实现需求的开发人员之间的隔阂一直困扰着软件的开发。近年来,出现一些基于动态语言和 DSL 的框架,它们尝试让代码读起来像一般语言一样,从而弥合利益相关者和开发人员之间的隔阂。本教程展示 easyb —— 提供一种更自然的、更适合利益相关者的 DSL —— 如何帮助开发人员和利益相关者有效地协作。

  开始之前

  关于本教程

   easyb 是一种用于 Java™ 平台的行为驱动开发(BDD)框架。easyb 使用基于规范的 DSL,目标是支持可执行的、易读的文档。您只需使用 Groovy 编写 easyb 规范,然后用可通过命令行、Apache Maven 2 或 Apache Ant 调用的 Java 运行程序执行它们。通过 easyb,可以更加方便地验证用 Java 代码编写的任何程序的行为。

  目标

  本教程逐步指导您掌握使用 easyb,以及利用案例与利益相关者进行协作。您将学习如何:

  使用利益相关者的词汇定义案例和场景

  用 easyb 实现它们

  通过 BDD 实践测试驱动开发(TDD)的真正目的

  完成本教程后,您将理解用 easyb 实现的协作案例的优点,以及这个框架如何使协作更加容易。

  先决条件

  为了充分利用本教程,您应该熟悉 Java 语法和 Java 平台上面向对象开发的基本概念。您还应该熟悉重构和常规单元测试。

  系统需求

  为实践并测试本教程的代码,需要安装以下产品之一:

  Sun's JDK 1.5.0_09(或更高版本)

  IBM® Developer Kit for Java technology 1.5.0 SR3

  另外还需要 easyb 和 Apache Ant。本教程提供了 easyb 和 Ant 的下载链接和安装说明。

  对于本教程,建议的系统配置是:

  支持 Sun JDK 1.5.0_09(或更高版本)或 IBM JDK 1.5.0 SR3 的系统,至少有 500MB 主内存

  至少有 20MB 的磁盘空间,用于安装软件组件和涉及到的示例

  本教程中的说明和示例基于 Microsoft® Windows® 操作系统。本教程中提到的所有工具也可以在 Linux® 和 UNIX® 系统上运行。

  需求和结果不匹配

  定义软件需求的人(利益相关者)与实现软件需求的人(开发人员)之间的隔阂由来已久。软件中的大多数缺陷都与需求误解有关,这与平台或应用程序无关。大多数企业都因软件不匹配需求而备受折磨 — 即使企业利益相关者认为他们之前已经很好地表达了自己的需求。

   近年来,为解决这个问题,已经出现了一些商业和开源解决方案。在开源方面,有 Fit 和 Fitnesse 框架。它们允许利益相关者编写规范(用表格式),然后由开发人员实现能够运行这些自定义需求的测试,从而试图弥合这种隔阂。然而,如果您花点时间了解一下 这类框架,就会发现隔阂依然存在。问题出在用于定义需求的媒介。

  人各相异

  一本流行的书用隐喻的手法提出这样的理 论:男人来自火星,女人来自金星。同样,利益相关者和开发人员也各有不同。完全可以这样说:利益相关者来自地球,他们使用的是日常的语言;而开发人员可能 来自不同的太阳系,他们使用的语言是一种代码,除编程人员外谁也看不懂。当将一般语言文档中定义的需求(用英语、汉语、法语、波斯语或任何其他语言编写 的)翻译成代码(用 Java 语言、Ruby、Python 或任何其他编程语言编写)时,总会出现需求和结果不匹配。因此,这个行业在压力测试、验证乃至跟踪方面花了数年的时间。但是,这一事实仍未改变:大部分利 益相关者不懂代码,而开发人员则用代码思考(可能很少讲一般的语言)。

  但是,近年来,随着动态语言的出现和特定与领域的语言 (DSL)的流行,出现了一些试图弥合利益相关者与开发人员之间的隔阂的框架。这些框架使代码看起来更像一般语言。这不是说利益相关者将开始编写代码。而 是开发人员开始编写代码时,对于应该编写什么代码的一般语言的描述使他们可以更好地与利益相关者协作。实际上,通过 easyb,需求(或规范说明)与实现它们的代码是逐字关联的。

  代码与一般语言描述一样

  考虑下面这条代码语句:

assertEquals(42.50, order.price(), 0.0)

  如果没有这条语句所在的上下文,这条代码有点难以理解。现在,想象您完全不读代码;也就是说,您是利益相关者,只是要求提供新的特性(并为之付费)。这样的代码语句显然不易阅读。

 现在,看看下面这条语句:

order.price().shouldBe 42.50

   虽然仍然没有这条语句所在的上下文,但是这条代码显得更清晰。实际上,它读起来像是一般的英语句子。它以更接近字面的方式描述行为:它使用像 shouldBe 这样的日常短语,这与另一个版本的 assertEquals 有明显的区别。在这里,利益相关者读这条代码时完全可以理解它。代码一开始就与利益相关者的要求一致。

  两个例子传达相同的意思,并 且验证 相同的需求。然而,order.price().shouldBe 42.50 非常贴近利益相关者使用的语言。这是 BDD 概念的基本点,它用词语 should 而不是 test 进行思考,力求更适当地验证软件系统。实际上,通过聚焦于行为并紧随利益相关者的要求对行为建模,BDD 遵从了可执行文档的思想。贴近利益相关者的语言可以减少需求与最终结果之间的不匹配。而且,使用利益相关者的语言便于所有参与方进行更深层次的协作。请 看:

 利益相关者:对于我们在线商店的下一个发行版,Gold 级别的顾客在购买东西时应该享受一定的折扣。开发人员:什么样的折扣?要享受这样的折扣,必须满足什么样的标准?利益相关者:他们的购物车 中至少有 $50。开发人员:折扣随总数而增加吗?还是无论购物车总价值多少,折扣都是固定的?利益相关者:问得好。无论价格如何,折扣固定为 15%。所以,对于一个 Gold 级别的顾客,当他们购物车中商品的总价值为 $50 或以上时,他们应该在总价的基础上享受 15% 的折扣。

  利益相关者的最后一句话是关键。注意,这句话实际上指定了需求以及验证它的方式。它讲述了一个与折扣有关的案例中的一个特定场景。

  实现所说的话

  对于一个给定的场景,开发人员可以按照字面逐字理解利益相关者的意见,并执行它们。easyb BDD 框架通过支持案例和场景的 DSL 为系统验证提供了便利。清单 1 实现了 Gold 级别折扣例子的需求:

  清单 1. 实现利益相关者的需求

scenario "Gold level customer with $50 in shopping cart", {
given "a Gold level customer"
when "their shopping cart totals $50 or more"
then "they should receive a 15 percent discount off the total price"
}

   这个特定的场景只是捕捉利益相关者的需求(这非常重要),所以认为它的状态是 pending。这一状态单独传达有价值的信息:首先一点,也是最重要的一点,利益相关者可以看到他们的话语,从而验证他们的要求。其次,他们可以判断自 己的需求是否已被实现。当这个场景被实现之后,它可能变成两种状态之一:success 或 failure,它们都向参与方传达了更深层次的状态信息。

  定义好协作场景后,开发就可以进入实现阶段。这里的精彩之处就在于,开发人员可以直接实现与需求一致的行为,如清单 2 所示:

  清单 2. 用 easyb 实现需求

scenario "Gold level customer with $50 in shopping cart", {
given "a Gold level customer", {
 customer = new GoldCustomer()
}
when "their shopping cart totals $50 or more", {
 customer.shoppingCart << new Item("widget", 50.00)
}
then "they should receive a 15% discount off the total price" , {
 customer.orderPrice.shouldBe 42.50
}
}

  现在,可以在应用程序上下文中执行该场景,以便进行验证。该场景正是利用利益相关者的话语。无论利益相关者阅读代码的能力如何,代码本身使用的就是自然语言:customer.orderPrice.shouldBe 42.50。

  通过利用利益相关者的语言,easyb 使利益相关者更容易帮助一起验证它们想要构建的系统。它在利益相关者想要的东西与得到的东西之间建立了直接的关联。

  easyb 入门

  easyb 的入门很容易。该框架被打包为一个 .tar.gz 归档文件。下载 最新的版本(撰写本教程时最新版本是 0.9),并将它解压到系统上的任意地方,例如一个 temp 目录。

   解压缩归档文件后,可以看到一个 easyb-0.9 文件夹,其中包含三个 JAR 文件:easyb.jar、commons-cli.jar 和 groovy.jar。为了让 easyb 能够工作,必须将它们添加到类路径中(对于任何其他 Java 工具都是如此)。

  详细的案例

  在接触更深入的内容之前,需要理解案例 的概念。回想一下在考虑一个需求时,利益相关者和开发人员之间的 对话。注意两个主要方面是如何从那次对话中发现的:

  一个特性

  Gold 级别的顾客应该享受折扣。

  一种验证该特性的方式

 如果购物车中有 $50(或更多),那么他们应该享受 15% 的折扣。(也就是说,如果在结账时购物车中刚好有 $50,那么他们应付的款是 $42.50)。

   在 BDD 领域,这被称作一个场景。场景是案例的一部分。在这里,有一个关于折扣的总的案例。一个特定的场景只关注购物车中商品价值为 $50 或以上的 Gold 级顾客的折扣。实际上,还可以有其他相关的场景,例如购物车中商品价值少于 $50 的 Gold 级顾客,或关于当购物车中商品价值超过 $200 时折扣按比例增减的场景。

  一个场景本身捕捉一个特性和用于验证该特性的一种方法,它使用特定的语言来描述这两个方面。仔细观察利益相关者的最后一句话,注意这句话中使用了 3 个关键词:given、when 和 then。

  “所以,对于一个 Gold 级顾客,当他们购物车中商品的总价值为 $50 或以上时,他们应该在总价的基础上享受 15% 的折扣。”

  这 3 个词将一个特性和用于验证它的一种方法绑定在一起,因为这些词描述了一个事件流或序列:

  给定某个上下文,

  当某件事发生时,

  就应该发生另一件事。

  而且,这 3 个词很容易串联起来,因为事件肯定可以变得比这个例子中更复杂。有些序列甚至不需要 when;也就是说,给定某个上下文,有时应该发生某件事。

  项目设置

  您已经下载了 easyb,并且知道什么是案例,现在应该设置一个项目。您将创建一个项目,配置该项目以便使用 easyb,并开始编写一个包含一些场景的案例,以验证顾客享受的折扣。

  遵循以下步骤:

  创建一个名为 acme 的新目录(可以随意命名)。该项目将包含构建一个软件应用程序所需的东西:源代码、库、构建系统和用于验证应用程序是否能按预期运行的 easyb 案例。(完整的示例代码参见 下载)。

  在 acme 目录中,创建 3 个子目录:

  lib,用于存放二进制依赖文件(比如 easyb-xx.jar)

  src,用于存放源代码

  stories,用于存放 easyb 案例

  将下载的 easyb 中的所有 3 个库文件(commons-cli、groovy 和 easyb)放到 lib 目录中。

  在 acme 根目录下创建一个名为 build.xml 的文件。

  项目自动化

   在开始编写案例之前,需要有一种方法来运行它们。虽然可以从命令行运行 easyb 案例,但是那样很麻烦。更好的方法是设置一个构建系统,以便自动编译代码和运行 easyb 案例。还可以运行任意的单元测试和部署应用程序等。通过将各种任务自动化,构建系统(这里是一个基于 Apache Ant 的构建系统)使您可以集中精力创建应用程序。

  安装 Ant

  build.xml 文件是一个 Ant 构建文件,所以需要安装 Ant,安装步骤很简单:

  下载 Ant 并解压到任意位置。(例如,我将它解压到 /home/aglover/tools/ant)。

  将 Ant 安装中的 bin 目录添加到路径中(所以,对我而言,将添加 /home/aglover/tools/ant/apache-ant-1.7.0/bin)。

  创建一个新的环境变量 ANT_HOME,并将它指向将 Ant 二进制文件解压到的位置(例如,/home/aglover/tools/ant/apache-ant-1.7.0/)。

  定义目标

  现在,Ant 已安装完毕,接下来您将为本教程剩下的部分定义一些目标。您最少需要 3 个目标:

  一个用于编译源代码

  另一个用于运行 easyb 案例

  还有一个用于清理生成的文件,以进行新的运行

  打开 build.xml 文件,添加清单 3 中的代码:

  清单 3. 默认的 Ant 构建文件

<project name="acme" basedir="." default="run-stories">
</project>

  清单 3 是一个 Ant 构建文件的基本定义。用这个文件运行 Ant 没有什么意义,所以在清单 3 中的两行代码之间添加清单 4 中的 XML:

  清单 4. Ant 中的源代码编译

<path id="build.classpath">
<fileset dir="lib">
 <include name="**/*.jar"/>
</fileset>
</path>
<target name="compile-source" description="compiles source code">
<mkdir dir="target/classes"/>
<javac srcdir="src/" destdir="target/classes">
 <classpath>
  <path refid="build.classpath"/>
 </classpath>
</javac>
</target>

  清单 4 中的 XML 定义:

  一个编译 src 目录中的源代码的任务

  一条包括 lib 目录中的二进制文件的路径

  接下来,添加这个 clean 目标:

<target name="clean"
  description="cleans out generated directory">
<delete dir="target"/>
</target>

  接着,添加一个运行 easyb 案例的目标。

  定义 easyb Ant 任务

  要从 Ant 运行 easyb 案例,首先必须通过 taskdef 任务配置 easyb Ant 任务,以便 Ant 能发现和执行它。然后就可以使用 easyb 任务。该任务本身有几个方面的要求:

  指定一个类路径,以便从中发现依赖的二进制文件和代码

  指定报告输出的类型

  指定一个路径,以便运行其中的案例

  幸运的是,可以用一段 XML 来完成这些任务,如清单 5 所示:

  清单 5. 在 Ant 中运行 easyb

<target name="run-stories" depends="compile-source">
<taskdef name="easyb" classname="org.disco.easyb.ant.BehaviorRunnerTask">
<classpath>
 <path refid="build.classpath"/>
</classpath>
</taskdef>
<easyb failureProperty="easyb.failed">
<classpath>
 <path refid="build.classpath"/>
 <pathelement path="target/classes"/>
</classpath>
<report location="target/stories.txt" format="txtstory"/>
<behaviors dir="stories">
<include name="**/**.story"/>
</behaviors>
</easyb>
<fail if="easyb.failed" message="easyb reported a failure"/>
</target>

  清单 5 中实现了很多事情,但是它仍然比较直观。首先,定义 run-stories 目标。它依赖于 compile-source 目标,后者负责编译源代码。案例本身将试验应用程序代码(这几乎与 JUnit 测试对待普通代码的方式一样)。

   接下来,通过 Ant 的 taskdef 任务装载 easyb 任务。这里提供了一个 <classpath>,它实际上告诉 Ant 在 lib 目录中进行查找,因为 easyb Ant 任务的代码就在这个目录中的 easyb-xx.jar 文件中。

  easyb 任务支持一个失败属性,当定义了这个属性时,如果一个案例失败,则可以让一个构建失败。这是一个很好的思想,因为定义可执行文档的总体思想是提供一个能按预期运行的应用程序。如果一个案例失败,这很可能说明事情没有按预期进行。

  然后,定义一个报告。在这里,目标指示 easyb 在 target 目录中创建一个名为 stories.txt 的文本案例报告。easyb 也支持其他报告格式,包括 XML 和 HTML。

   behaviors 元素定义 easyb 在何处可以找到案例。在这里,easyb 将在 stories 目录中查找以 .story 为后缀的文件。.story 扩展名是一个 easyb 约定;但是,也可以用 .groovy 作为案例文件的扩展名,前提是 以 Story 作为文件名的结尾。例如,Discounts.story 和 DiscountsStory.groovy 都是有效的 easyb 文件名。

  最后,结合前面设置的失败属性(easyb.failed)利用 Ant 的 fail 任务。如果设置了该属性,Ant 将触发一个失败条件,并发出消息 easyb reported a failure。

  完成这些步骤后,项目现在可以自动运行 easyb 案例。而且,如果一个案例失败,那么构建将失败,从而提供关于代码基的状态的有价值的反馈。

  定义案例

  您已经看到,案例以一种开发人员和利益相关者都能读懂的标准格式捕捉需求并验证需求。而且,您看到了在一次对话中详尽说明的一个场景。至此,您对于什么是案例和场景有了更好的理解,现在可以试着动手实现新的案例和场景。

  一次新的对话

  想象一下,前面的那个折扣案例中的场景已经被实现,客户对这个特性非常满意,因此还想要另一个特性。和前面一样,可以在一次对话中展现相关的细节。

 利 益相关者:我们的 Gold 级顾客对于 $50 或以上的订单能享受 15% 的折扣感到非常满意。我们认为对于非 Gold 级的顾客也给予一定的奖励是个不错的主意。 开发人员:什么样的奖励?利益相关者:当一个非 Gold 级的顾客购买 $100 或以上的商品时,他们应该享受 $10 的折扣;而且,他们应该收到一张优惠券,将来购买东西时可以使用。开发人员:无论价格如何(假设超过 $100),$10 的折扣都是固定的吗?利益相关者:是的,不受影响。我们对顾客购买习惯的分析表明,非 Gold 级顾客很少购买超过 $250 的商品。开发人员:这些顾客如何接收优惠券? 利益相关者:系统应该通过电子邮件发送给他们。几个月前我们已经实现了一个优惠券服务,所以只需使用那个服务。开发人员:好的,也就是说,对于一个给定的非 Gold 级顾客,当他们购物车中的商品总价为 $100 或以上时,他们应该享受 $10 的折扣,并且通过电子邮件收到一张优惠券。利益相关者:完全正确!你们什么时候可以完成?

   和前面一样,利益相关者(或者说客户)设法清楚地表达他/她想要什么。注意,利益相关者相当自然地使用词语 should。而 test 这个词根本没有出现,如果出现了这个词,听起来会有些奇怪。然后,开发人员听取客户的话语,并使用一个场景的关键元素以更正式的方式描绘客户想要的 东??。

  有了用于定义案例和场景的规范化结构之后,开发人员甚至利益相关者就可以利用 easyb 的 DSL 将对话编写成代码。

  第一步是创建一个案例文件。在就顾客折扣的想法作了更细致的讨论之后,在项目的 stories 目录中创建一个新的名为 CustomerDiscounts.story 的文件。

 在编辑器或 IDE 中打开那个文件。例如,如果您是 Eclipse 用户,那么可以在您的环境中轻松地定义案例文件,编辑它们,甚至运行它们。这个过程需要执行 easyb 的 BehaviorRunner;要了解更详细的信息,请参阅 easyb 的文档。

  在 CustomerDiscounts.story 中,您将定义一个场景。场景定义使用清单 6 中显示的语法:

  清单 6. 场景语法

scenario "description", {}

  最后一部分(逗号后面接两个花括号)是可选的。如果省略这部分,easyb 会将定义的 scenario 视为 pending 状态。

  将清单 7 中的这行代码添加到 CustomerDiscounts.story 中:

  清单 7. 定义一个场景

scenario "Non-Gold level customer with $100 or more"

  由于在 Groovy 中美元符号($)实际上是一个分隔符,所以需要在它前面加一个 进行转义。

  现在,运行 Ant 构建的 run-stories 任务,如清单 8 所示:

  清单 8. 通过 Ant 运行 easyb

/home/aglover/Development/acme$ ant run-stories
Buildfile: build.xml
compile-source:
run-stories:
 [easyb] easyb is preparing to process 1 file(s)
 [easyb] Running customer discounts story (CustomerDiscounts.story)
 [easyb] Scenarios run: 1, Failures: 0, Pending: 1, Time Elapsed: 0.534 sec
 [easyb]
 [easyb] 1 behavior run (including 1 pending behavior) with no failures
 [easyb] easyb execution passed
BUILD SUCCESSFUL
Total time: 2 seconds

  可以看到,easyb 执行了您的案例:一个场景被运行,它处于 pending 状态。

 您应该记得,在配置 Ant 任务以便运行 easyb 任务时,您还指定了想要基于文本格式的报告 stories.txt。您让 easyb 在 target 目录中生成这个报告。看看 stories.txt,它应该如清单 9 所示:

  清单 9. easyb 报告

1 scenario (including 1 pending) executed successfully
Story: customer discounts
 scenario Non-Gold level customer with $100 or more
  given a non-Gold level customer
  when they have $100 or more in their shopping cart
  then they should receive a $10 discount
  then they should be e-mailed a coupon [PENDING]

  可以看到,这个报告可以作为供利益相关者查看的很好的材料,因为它用普通语言重复了需求。还应注意,您的场景被认为处于 pending 状态。

  easyb 中的状态

   在 easyb 中,场景 — 不是案例 — 有一定的状态。一个场景可处于 passing、failing 或 pending 状态。pending 很方便,因为它可以表明一个特定场景正在被积极地处理。而 failing 显然表明被验证的应用程序或定义场景的方式中存在错误。

  easyb 中的场景使用关键词 given、when、then 和可选的 and 定义步骤。在一个场景中,每个关键词定义看上去很像 scenario 关键词定义,如清单 10 所示:

  清单 10. 关键词的 DSL 语法

keyword "description", {}

  和 scenario 一样,逗号和花括号是可选的。花括号实际上是 Groovy 中的一个闭包,所以从现在开始我将使用那个术语。

  协作案例

  在本节前面利益相关者和开发人员之间的对话中,当开发人员像下面这样说时,实际上就定义了一个场景:

 “对于一个给定的非 Gold 级顾客,当他们购物车中的商品总价为 $100 或以上时,他们应该享受 $10 的折扣,并且通过电子邮件收到一张优惠券。”

  回到 CustomerDiscounts.story 文件,将场景细节编写成代码,如清单 11 所示:

  清单 11. 在 easyb 中将场景细节编写成代码

scenario "Non-Gold level customer with $100 or more" , {
given "a non-Gold level customer"
when "they have $100 or more in their shopping cart"
then "they should receive a $10 discount"
and "they should be emailed a coupon"
}

  通过 Ant 运行该案例。应该可以看到,结果与前面一样;也就是说,场景仍然处于 pending 状态。我们花点时间来理解一下其中发生了什么事情。这个场景有 4 个步骤,这 4 个步骤定义了:

  给定某个上下文,

  当某件事发生时,

  那么应该发生某一件不同的事,

  而且还应该发生另外一件事。

  可以看到,在这里,最后一个 and 的字面意思是 then。在 easyb 中,and 可以有任何其他 3 个关键词的意思;实际上,它的意思与它前面的关键词的意思。

  现在,场景已被代码化,它变得更便于利益相关者与开发人员之间的协作,因为他们有一个共同的用于讨论的媒介。每个人都看着相同的东西。双方都可以就模糊之处进行讨论,或者解决疑问。例如,何时向顾客发生电子邮件?立即?还是以后某天?

   开发人员:电子邮件应该什么时候发出?我们可以在成功购买后立即发送,或者在指定的时间内发送。利益相关者:啊,我们还没有真正考虑这一点。那就 24 小时后发送吧。这样的话,顾客就会再回来,并使用优惠券。如果我们立即发送电子邮件,那么它可能被遗忘,因为他们刚买了东西。 开发人员:那么,如果他们花费了 $100 或以上,他们将只收到一封电子邮件,对吗?利益相关者:是的。开发人员:$10 的折扣 — 是用于当前的购物,还是在以后使用?利益相关者:应该应用到当前的价格上,所以他们在总价的基础上应该享受 $10 的折扣。

  这段对话为澄清本来模糊的场景提供了细节。更新场景,添加这些细节,如清单 12 所示:

清单 12. 更新场景

scenario "Non-Gold level customer with $100 or more" , {
given "a non-Gold level customer"
when "they have $100 or more in their shopping cart"
then "at the time of checkout, they should receive $10 off the total price"
and "they should be emailed a coupon within 24 hours"
}

  以它的一个场景运行这个案例仍然会产生一个 pending 结果。现在也许是时候开始插入某种行为了,对吗?

  实现案例

   虽然 easyb 案例是 Groovy 脚本,easyb 的使用却不限于 Groovy。实际上,easyb 案例??容易验证 Java 应用程序,因为 Groovy 与 Java 代码是无缝集成的。而且,Groovy 的语法很灵活,所以很容易在一个案例文件中编写常规的 Java 代码,跳出 Groovy 的框架。

  TDD,正式的定义

  TDD 有很多不同的定义,所以很多人在被问到他们是否在实践 TDD 时,常常感到困惑。可以这么说,TDD 的形式之一就是测试优先开发(test-first development)。测试优先开发实际上主张首先编写一个失败的测试,然后编写足够的代码使测试通过,接着再编写另一个失败的测试,然后再编写足够 的代码使之通过。重复这一过程,直到手头的任务完成,这样才算是实践了一个严格意义上的 TDD。所以说,很少有开发人员真正每天都这样做。

   BDD 则把重点放在以更自然的方式表达规范说明(通过强调 should 这个词)上,结果成为测试优先开发精神下更有效的驱动开发的方式。本教程从开始现在都采用这条路线。您首先编写了一个规范说明。现在它处于 pending 状态。接下来的步骤是让场景处于 failing 状态。然后,您将编写足够的代码使这个场景通过。猜猜然后您将做什么?对了:您将编写另一个场景,使代码失败,重复这个过程,直到满足了手头上的需求。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics