RSpec 增加了众所翘首以待的 RBehave 功能以供集成测试所需

  • Sean Miller
  • 张海龙

2007 年 10 月 31 日

话题:敏捷Ruby测试语言 & 开发架构文化 & 方法

RSpec是 一个为 Ruby 编写的基于行为驱动开发(简称 BDD,即 Behaviour-Driven Development)的验收测试框架,同时也可用于 Java(事实上它一直都可以运行于 JRuby 中),它提供了一种机制,即由开发人员从业务中获取 验收标准并将它们转换为可读、可运行的示例,以此替代文档、测试和适用于业务的构建报告。

尽管 RSpec 对单元级测试很有用,但它在集成测试中一直存在一个盲点。Dan North 创建了一个独立的扩展,RBehave,它用 Given…With…Then…这样的格式以一系列的步骤从故事级别来描述行为。(North 最早是在JBehave中描述了这种用于获得需求故事的模式)

David Chelimsky 现在已经向 RSpec trunk 中合并了一个纯文本故事运行器(Plain Text Story Runner),它给 RSpec 添加了 RBehave 功能,就像他 他的 博客中描述的那样。

现在看看 North 的经典 RBehave 示例:

So, North's classic RBehave example:

require ‘rubygems’

require ‘rbehave’

require ’spec’ # for "should" method

require ‘account’ # the actual application code

Story "transfer to cash account",



%(As a savings account holder

  I want to transfer money from my savings account

  So that I can get cash easily from an ATM) do

  Scenario "savings account is in credit" do



    Given "my savings account balance is", 100 do |balance|

      @savings_account = Account.new(balance)

    end

    Given "my cash account balance is", 10 do |balance|

      @cash_account = Account.new(balance)

    end

    When "I transfer", 20 do |amount|

      @savings_account.transfer_to(@cash_account, amount)

    end

    Then "my savings account balance should be", 80 do |expected_amount|

      @savings_account.balance.should == expected_amount

    end

    Then "my cash account balance should be", 30 do |expected_amount|

      @cash_account.balance.should == expected_amount

    end

  end

  Scenario "savings account is overdrawn" do



    Given "my savings account balance is", -20

    Given "my cash account balance is", 10

    When "I transfer", 20

    Then "my savings account balance should be", -20

    Then "my cash account balance should be", 10

  end

end

在新的 RSpec 中它可以变成这样,由一个 Ruby 文件定义可用的步骤:

class AccountSteps < Spec::Story::StepGroup

  steps do |define|

    define.given("my savings account balance is $balance") do |balance|

      @savings_account = Account.new(balance.to_f)

    end

    define.given("my cash account balance is $balance" do |balance|



      @cash_account = Account.new(balance.to_f)

    end

    define.then("my savings account balance should be $expected_amount" do |expected_amount|



      @savings_account.balance.should == expected_amount.to_f

    end

    define.then("my cash account balance should be $expected_amount" do |expected_amount|



      @cash_account.balance.should == expected_amount.to_f

    end

  end

end

steps = AccountSteps.new do |define|



  define.when("I transfer $amount") do |amount|

    @savings_account.transfer_to(@cash_account, amount.to_f)

  end

end

在一个纯文本文件中按照那些步骤定义故事的行为:
Story: transfer to cash account

  As a savings account holder

  I want to transfer money from my savings account

  So that I can get cash easily from an ATM

  Scenario: savings account is in credit



    Given my savings account balance is 100

    And my cash account balance is 10

    When I transfer 20

    Then my savings account balance should be 80

    And my cash account balance should be 30

  Scenario: savings account is overdrawn



    Given my savings account balance is -20

    And my cash account balance is 10

    When I transfer 20

    Then my savings account balance should be -20

    And my cash account balance should be 10

由一个 Ruby 文件将他们粘在一起,并运行这些故事:

require 'spec'

require 'path/to/your/library/files'

require 'path/to/file/that/defines/account_steps.rb'

# assumes the other story file is named the same as this file minus ".rb"



runner = Spec::Story::Runner::PlainTextStoryRunner.new(File.expand_path(__FILE__).gsub(".rb",""))

runner.steps << AccountSteps.new

runner.run

纯文本文件中的那些步骤描述,必须与 StepGroup 中定义的步骤相匹配,这些描述可能会随着步骤数量的增加变得难以理解。Aslak Hellesøy 正在为一个基于浏览器的编缉器工作,它将提供步骤的自动补全,并可以在恰当的位置对参数进行编辑,从而使这一问题得以简化。

查看英文原文RSpec Trunk Now Includes RBehave-like Story Runner

敏捷Ruby测试语言 & 开发架构文化 & 方法