.NET 互操作

使用 IronRuby 自动执行验收测试

Ben Hall

代码下载可从 MSDN 代码库
浏览代码联机

本文讨论:

  • 什么验收测试?
  • 自动的验收测试
  • 实现验收测试
本文涉及以下技术:
IronRuby

内容

什么验收测试?
自动接受测试
文章
方案
执行验收测试
与 C# 对象进行交互的 RSpec 方案 Runner
验收测试用户界面
向前移动

当客户要求可以被正确传递而不必浪费时间实现不完整或不正确功能日的几乎每个开发人员 dreams。岂不是很好如果我们未能向客户手动清除,可读规格并要求他们是否与匹配后中,我们可能运行不为验证是否根据这些要求实现任何其他努力完全该同一规格其功能要求?

使用接受测试和可执行文件规范的概念,可以成功地完成此级别的客户和开发人员之间的通信。通过利用驱动开发 (BDD) 的行为,我们可以开始通信要求更有效地。

2 月 2009 月刊中我文章中MSDN 杂志 》("入门 IronRuby 和 RSpec,第 1 部分"),我引入 IronRuby 并演示如何它允许您使用动态拼写的语言与.NET 兼容代码 (如 C# 互操作。本文,我将向您介绍验收测试的概念。通过我以前的文章中引入的概念的构建,我将演示如何验收测试才能自动使用 IronRuby 和 RSpec 验证.NET 应用程序,并创建为系统的可执行文件规范。

什么验收测试?

验收测试已与许多不同的定义。对于我,验收测试是更多有关验证开发系统满足客户的要求和有关减少在代码中的错误数较少。换句话说,验收测试将是不是有关测试代码,但有关生成哪些客户或业务需要。这听起来很明显,但缺少验收测试和了解要求类似缺乏主要原因很多项目失败。

验收测试仅适用于支持该的客户或在至少一个代理客户,可帮助定义条件。没有人推动验收标准您没有要进行验证软件正确,这使得难以验证要生成正确的软件。在客户一起开发团队的所有成员应一起来自定义方面可测试"方案"介绍系统必须执行和如何它必须实现它的许多系统。

例如如果我们已开发的电子开始系统,一个验收测试可能基于购物车的交互。典型的方案可能,"如果购物车为空,我添加产品 123,然后项目计数应增加为 1 并且分类汇总应为 ¥20"。 这提供了解如何客户期望购物车,行为,并提供验证实现一些步骤。随着系统的增长您必须验证系统和功能集的不同部分的多个方案。

还的重要的考虑因素编写方案时是使用的语言。所使用的语言应反映业务如何了解该的问题不如何开发人员将实现该解决方案。如果测试描述的实际的实现"当我单击按钮标签确认更改提交",则这将向客户提供较少的值并将依赖于如何实际实现系统。如果这些实际的实现更改但业务要求保持不变,然后该依赖项将需要额外的维护成本为该团队必须更新相关的测试。

通过清除的要求和传递条件创建测试,软件表示会议客户的期望的多好机会。但是,这仍需要用户手动验证满足了要求和应用程序正常工作。这是其中自动的接受测试的理念有。而不是文件共享上过期文档中被要求,要求被定义为示例和方案,到与实现的项目的源代码管理签并可以随时以验证是否实现任何要求和正常运行。您可以将同样的方法编写该的测试的但编写而它们在测试用例管理软件或电子表格中,不是您编写其代码中直接

自动接受测试

验收测试有助于验证您构建客户而自动执行这些方案允许您不断验证整个开发过程的实现,和它们使用作为您的回归测试套件的一部分,以确保以后的更改不违反存在要求需要应用的程序。

但是,具有客户涉及编写尤其是自动测试的测试,引入了许多潜在的问题。一般情况下,客户,将 nontechnical,并倾向于 shy 离实际开发的软件。通过与技术团队协作,客户可以提供输入和测试人员时的示例,或开发人员可以快速编码方案和可执行文件的规格。此外,方案必须清除任何业务中。通过 IronRuby 可以提高可读性测试,但如何执行在实践中的此工作的?

若要说明如何此过程可能用于实际项目,我将演示实现周围价格计算系统的一个用户部分。一个简单的示例但希望它将演示所涉及的步骤。验收测试的可以在如何处理该的问题是一个框架,并且有很多变种和解释。然而,这应提供您允许您向前转并找出的详细技术工作的基本概念。

此示例附带超出"红色、 绿色,Refactor"我为在本地用户组的演示文稿。之后,与会者之一要求我建议在如何他可以有效地单元测试其应用程序以确保所有价格计算,包括各种选项和添加到包,已被正确都计算。此示例是一个完全演示验收测试的非常有用。通过一个文字部分和价格和您希望发生这种情况的方案,您可以确信系统正常工作。

这些验证也将变为有用的开发团队和客户来演示不同的示例系统的工作方式以及各种异常文档源。如果客户认为的价格不对,则团队可以引用客户批准作为完成工作的证据可执行文件规范。

不在位置这些测试周围定价规则将可能中定义大试图说明系统处理各种定价配置-本质上断开系统开发的文档的 Word 文档。这就是为什么我相信自动的验收测试的原因。

文章

在开发使用验收测试的目的的价格计算系统时第一个阶段是让 Everyone 一个房间内定义文字部分。客户定义所需使用 encouragement 从团队的技术成员。使用 BDD,以前的文章中提到要使用集格式用于定义内容以支持一种一致的语言之间团队,和具体来说是客户所需的成员。给定以下格式,将填写帮助客户详细信息:

为 [角色] 我希望 [功能] 因此 [结果]。

直接的错误通常是启动包括篇文章中的实现细节。例如:

以管理员身份,我希望在 Default.aspx,栅格视图中显示的价格,以便与成本将它们提供。

文字部分必须仅在特定的业务方面描述问题并调整清除的技术详细信息。改进了的示例可能是这样:

作为一销售管理员我希望被标识为客户,以便与成本将它们提供的价格。

遗憾的是,它遵循格式时, 它提供了一些很松散的信息并它不会将起始点为实现。更好的示例是:

作为一销售管理员希望能够查看价格产品 x,以便我可以为客户提供根据其要求的准确成本。

这篇文章向我们提供更多详细信息和有关哪些客户需要发生和他们真正想的多个上下文。结果,它是对我们非常有用实现系统时。

记住编写案例和功能时的一个重要事实是使其为尽可能集中。将使其更易于创建方案,编写该的测试和实现完成的代码。某些的系统可能是文章基础围绕一项功能。

方案

即使有一篇的文章您仍需要发生需要的内容的详细信息。方案可非常用于此。一个方案只是指出在某些上下文指定如果出现问题 (输出应为此。目的是提供一个更具体的示例文章的实现应在不同情况下的行为方式。这将通信给团队的期望,并提供用于验证的步骤。

要使用推荐的语法称为给定,时,然后 (GWT) 语法由 Dan North 升级:

当指定 [上下文],[出现问题],然后 [结果]。

示例方案可能如下:

不支持的方案: 单用户许可证的产品 X

产品 X 给定当用户请求一个用户许可证,而这不包括支持,然后价格应为 ¥250。

使用","能用于连接多个上下文或结果,以便您可以提供更多的意义方案并提供有关所发生的情况的更多信息。

理想情况下,应该有许多情况下,以解决任何多义性,作为该可执行文件的规格并提供初始工作开始的足够的信息。值得注意不修复这些方案。为工作继续并获得更多知识,您可能需要返回到客户有关现有方案的问题或创建基于获得的知识的其他方案。

编写方案时, 会有一些事项需要注意。与案例,方案应将侧重于一个示例。为此,主要原因是可读性。如果方案执行过多,然后将该核心消息会丢失。

执行验收测试

一旦拥有文章和方案清除、 易于理解的格式下, 一阶段是自动执行部分和方案。这样,他们要来跟踪进度,并捕获回归错误的开发过程中运行。同时我将会讨论方面 RSpec,基本过程可以传送到任何 BDD 框架中。有关安装 IronRuby 以及RSpec 的详细信息,请参见我前面提到的文章。

如果您按照前面示例编写您的案例,然后您会发现方案 Runner RSpec 中很自然。将普通的空文件中文件名为 pricing_scenarios_for_product_x,本例中您只需复制文章和方案到该文件按以下格式:

Story: Pricing for New Product X
  As a sales administrator, I want to be able to view
  prices for product x so that I can provide customers
  with an accurate cost for their requirements. 
Scenario: Single User License for Product X without support
  Given Product X
  When user requests a 1 user license
  And this does not include support
  Then the price should be $250

这现在基础我们验收标准,并验证应用程序时将被使用。 但是,以便其作为该可执行文件的规格,您需要一些拼写的代码来执行它们。 IronRuby 是一个简单的环境,以启动写入和执行代码。 只需创建一个文件使用.rb 扩展名,并重开始编写 RSpec 测试。

第一步是引用 RSpec 框架。 这是通过要求指令。 因以下两行可以启动使用 RSpec 文章 Runner:

require 'rubygems'
require 'spec/story'

现在您可以定义步骤。 一步是在使用 GWT 格式的方案。 与 RSpec,一个步骤就是与代码中的方法。 每个步骤应与执行只有一个任务关联。 是例如在给定的步骤设置对象使用,时然后通常是声明和验证的出现位置。

使用 RSpec,所有步骤都需要调用 steps_for 块中换行。 在方括号内是的步骤集标识符:

steps_for(:product_x) do
  #Steps go here
end

每个篇文章中步骤直接与方案中的行。 是例如 RSpec 代码中的"提供产品 X"的行将对应于下面的步骤方法:

Given("Product $productName at $price") do |productName, price|
   pending "Need to complete implementation for accessing C# object"
 end

RSpec 将执行的字符串操作允许您在您的步骤中使用占位符,占位符值为一个变量设置为在步骤。 在这种情况下名称和价格将存储在该的变量可以重复使用多个不同的产品和基价相同的步骤。

遵循相同的方法时,然后的步骤:

  When("user requests a $amount user license") do |amount|
    pending "Need to complete implementation for accessing C# object"
  end
  When("this does not include support") do
    pending "Need to complete implementation for accessing C# object"
  end
  Then("the price should be $price") do |price|
    pending "Need to complete implementation for accessing C# object"
  End

您不需要第二个步骤的占位符因为始终是相同的操作在块没有参数。 当您执行测试时,RSpec 将调用正确的方法按正确顺序基于该的方案定义替换值。

最后,您需要提供文章文件首先创建路径。 这是调用 with_steps_for,提供定义步骤时使用该标识符的另一个块。 正文调用运行的方法具有路径和文件存储方案的名称:

with_steps_for(:product_x) do
  run File.dirname(__FILE__) + "/pricing_scenarios_for_product_x"
end

要执行测试,运行 IronRuby 命令行工具 (ir),将作为参数传入拼写文件:

>ir pricing_scenarios_for_product_x_story.rb

写入步骤,时您会发现我已调用挂起的方法。 这是为了表示存在仍需要完成功能的工作。 因此,当我运行了测试,输出将声明的所有挂起的任务 (请参见 图 1 )。 这是很好的可读性和了解所发生的情况,最后的内容所需为该步骤将传递,因为没有任何实现。

图 1 的显示挂起的方法

Running 1 scenarios
Story: Pricing for New Product X
 As a sales administrator, I want to be able to view prices for product x, 
 so that I can provide customers with an accurate cost for their requirements.
 Scenario: Single User License for Product X without support
  Given Product X at 250 (PENDING)
  When user orders a 1 user license (PENDING)
  And this does not include support (PENDING)
  Then the price should be 250 (PENDING)
1 scenarios: 0 succeeded, 0 failed, 1 pending
Pending Steps:
1. Pricing for New Product X (Single User License for Product X without support): Product $productName at $price
2. Pricing for New Product X (Single User License for Product X without support): user orders a $amount user license
3. Pricing for New Product X (Single User License for Product X without support): this does not include support
4. Pricing for New Product X (Single User License for Product X without support): the price should be $price

与 C# 对象进行交互的 RSpec 方案 Runner

到目前为止该文章、 方案和步骤位于的位置。 但是,我们未实现任何代码与我们的系统进行交互。 我以前的文章我重点如何使用 RSpec 规范框架提供了我的 C# 对象工作和验证它们的实现作为一个独立单元的方式的示例。 此文章中, 我们正在查看如何使用 RSpec 文章 Runner 接受测试、 侧重于验证完整的应用程序堆栈,而不是独立的块。

在第一个任务是引用 C# 程序集。 IronRuby 保存 True 以拼写的语言构造,并因此,引用 C# 库与引用拼音库相同:

require File.dirname(__FILE__) + 
  '/CSharpAssembly/CSharpAssembly/bin/Debug/CSharpAssembly.dll'

现在我们可以开始编写的我们方案,我们在上一节中定义的主体。 要传递方案,我们需要实现该函数用于计算订单的总价格。 在给定的块内您初始化该方案所需的对象。 我们方案,初始化所需的唯一对象现在是产品对象。 对象的构造函数需要产品名称和价格。 同时从方法参数又从该方案本身获取获得:

  Given("Product $productName at $price") do |productName, price|
    @product = CSharpNamespace::Product.new(productName, price.to_i)
  end

获得初始对象后,我们需要将我们的测试的主题的这些对象上设置变量的状态,发生时块。 在我们的情况下,我们状态用户已订购特定数量的许可证,并且我们步需要反映这并相应地设置对象状态:

  When("user orders a $amount user license") do |amount|
    @order = CSharpNamespace::Order.new(@product)
    @order.NumberOfLicenses = amount.to_i
  end

最后,我们是部分,我们实际上验证上述操作正常。 我们然后的块中,我们定义我们期望和声明。

此处,我们花的顺序我们创建并验证分类汇总不会匹配在我们的方案定义该价格。 应将扩展方法创建动态由 RSpec 使我们能够验证我们的语句的事实的所有对象 ; 如果它并不 true,然后则会引发一个异常:

  Then("the price should be $price") do |price|
    @order.Subtotal.should == price.to_i
  end

现在,我们可以通过使用下面的命令执行文章:

>ir pricing_scenarios_for_product_x_story.rb

执行每个方案、 RSpec 将输出文章和方案以控制台,如果某个步骤失败时, 将突出显示特定的问题并指示末尾总数:

Running 1 scenarios
Story: Pricing for New Product X
  As a sales administrator, I want to be able to view prices for product x, 
  so that I can provide customers with an accurate cost for their requirements.

  Scenario: Single User License for Product X without support

    Given Product X at 250
    When user orders a 1 user license
    And this does not include support
    Then the price should be 250 (FAILED)

1 scenarios: 0 succeeded, 1 failed, 0 pending

如果所有成功,然后以下应显示在命令行上:

Running 1 scenarios
Story: Pricing for New Product X
 As a sales administrator, I want to be able to view prices for product x, 
 so that I can provide customers with an accurate cost for their requirements.
 Scenario: Single User License for Product X without support
  Given Product X at 250
  When user orders a 1 user license
  And this does not include support
  Then the price should be 250
1 scenarios: 1 succeeded, 0 failed, 0 pending

此时我们可以开始创建附加的、 更复杂方案,以包括更多的业务逻辑。 是例如可以查找这样的方案中包括该的价的折扣:

Scenario: Single User License for Product X with 20% discount 
and includes 2 years unlimited premium support.
   Given Product X
   When user requests a 1 user license
   And including 2 years support
   And support length is unlimited
   And support type is premium
   And with 20% discount
   Then the price should be $800

如前面提到这些情况下将使用业务术语,使其在业务不仅不是客户,但任何人都可读。

验收测试用户界面

在我的示例,以便测试是否逻辑正常专注于业务逻辑和域对象在验收测试。 但呢如何用户与应用程序交互? 这些验收测试应该有验证逻辑是否正确从用户的角度来看,该用户的角度来看,在用户界面。

个人,我认为验收测试应侧重于应用程序逻辑和决定要执行以下重要部分代码。 如果您的应用程序具有,好 decoupling 和从用户界面代码正确分离逻辑,这会使测试更容易实现。 如果您要测试此级别,测试不会更改受影响到 UI。

测试仅应该关注逻辑时, 这并不意味着您不应具有 UI 围绕任何验收测试。 我喜欢有在核心"快乐路径"UI 的目标的一组冒烟测试。 在关注用户最可能使用的大多数值从最少量的测试目的的应用程序的部分。 如果您尝试涵盖所有可能的路径和在的 UI 的使用,并且在用户界面更改 (如移动到不同的对话框的选项),则将需要更改所有测试。

是例如如果您已测试的电子商务站点 UI,快乐的路径将为向选择项目、 将其添加到您的购物车、 签出,以及查看采购的确认。 如果将失败这种情况下您真正需要知道越早越好。

对于某些,根据上应用程序的复杂性和寿命,您可能需要有更多的验收测试以确保在 UI 层拥有更多的信任 UI 上运行。 成功测试用户界面是一个复杂的主题但,我没有足以此空间。 我建议阅读我 博客发布项目上用于测试 WPF 白色用于测试 Web 应用程序的 WatiN. 此外,James McCaffrey 已写入 使用 Windows PowerShell 的 UI 自动化2007 年 12 月发布的 MSDN 杂志 》 .

向前移动

到目前为止,现在可以开始将 IronRuby 从事验收测试。 该信息应让您启动,但您应记住的一些事项。

一个可能的问题是这时 IronRuby 不供生产使用。 虽然您可以立即使用它,有正在继续开发和 IronRuby 和 RSpec 的优化。 这意味着 Bug 修复而且重要更改的可能性。 另外还有问题的 RSpec 的执行速度。 但是,值得评估该问题是否超过简化测试中的优点。

有些人可能充当一些的另一个问题与上下文切换。 通常,人员想编写测试和生产代码相同的语言。 通常同意,单元测试执行大量的每日的开关时您可能不需要使用 IronRuby 和 RSpec。 但是,进行验收测试,量所需的上下文切换是更低。 因此,我认为可以调整上下文切换到利用可读性和编写的验证和方案,因为它们将客户和开发团队提供极大的好处的更自然的方式。

最后,集成验收测试到开发过程可以是为开发组织一个 hugely 正步骤。 通过使用技术,例如案例和方案结合可读的但自动验收测试面向客户的条件中, 定义的功能,将能够使用您的客户创建更受信任的合作关系,并始终提供更强大和可靠的软件。

Ben Hall 是英国 C# 开发 / 测试人员与 for Software Development 的强热情。 他喜欢编写代码。 Ben 的工作方式在红色 Gate 软件测试工程师,并且受浏览包括手动和自动测试、 测试不同类型的应用程序的最佳方式所关注的测试软件的不同的方式。 Ben 是 C# MVP,并维护在博客 Blog.BenHall.Me.uk