rspec-given亦是Jim Weirich的作品。given、when、then的引入,让测试变得更方便。

rspec-given

rspec-given的写法十分直接了当:

describe "Character has name" do
  Given(:guy) { Character.new("George") }
  Then { guy.name.should == "George" }
end

Given指定测试的预设,Then指定需要检测的断言。

那么,如果我想更改上面角色的姓名呢?我需要确保更改操作确实有效,这就要用到When

describe "Character has name" do
  Given(:guy) { Character.new("George") }
  Then { guy.name.should == "George" }

  describe "changing the name" do
    When { guy.name = "Bill" }
    Then { guy.name.should == "Bill" }
  end
end

来看一个复杂一点的例子吧,测试角色生命值的增减是否有效:

describe "Character can be damaged" do
  LOSING_DICE_ROLL = 2
  WINNING_DICE_ROLL = 19
  CRITICAL_DICE_ROLL = 20

  Given(:attacker) { Character.new("Attacker") }
  Given(:defender) { Character.new("Defender") }
  Given!(:original_hp) { defender.hit_points }

  Invariant { defender.should be_alive }

  When { attacker.attack(defender, dice_value) }
  Given(:change_in_hp) { defenders.hit_points - original_hp }

  context "when the attacker misses" do
    Given(:dice_value) { LOSING_DICE_ROLL }
    Then { change_in_hp.should == 0 }
  end

  context "when the attacker hits" do
    Given(:dice_value) { WINNING_DICE_ROLL }
    Then { change_in_hp.should == -1 }
  end

  context "when the attacker gets a critical hit" do
    Given(:dice_value) { CRITICAL_DICE_ROLL }
    Then { change_in_hp.should == -2 }
  end
end

值得注意的有两点:

我们定义了LOSING_DICE_ROLL之类的常量,这样设定变更之后只要修改一处。

我们使用了Invariant,它会在每次执行作用域内的Then前执行。上面示例中的Invariant确保生命值增减前角色仍然存活(增减死人的生命值可没有意义)。

上面我们提到了Invariant针对作用域内的Then有效,下面给出一个例子:

describe "Character can be damaged" do
  LOSING_DICE_ROLL = 2
  WINNING_DICE_ROLL = 19
  CRITICAL_DICE_ROLL = 20

  Given(:attacker) { Character.new("Attacker") }
  Given(:defender) { Character.new("Defender") }
  Given!(:original_hp) { defender.hit_points }

  When { attacker.attack(defender, dice_value) }
  Given(:change_in_hp) { defenders.hit_points - original_hp }

  context "where the defender survives" do
    Invariant { defender.should be_alive }

    context "when the attacker misses" do
      Given(:dice_value) { LOSING_DICE_ROLL }
      Then { change_in_hp.should == 0 }
    end

    context "when the attacker hits" do
      Given(:dice_value) { WINNING_DICE_ROLL }
      Then { change_in_hp.should == -1 }
    end

    context "when the attacker gets a critical hit" do
      Given(:dice_value) { CRITICAL_DICE_ROLL }
      Then { change_in_hp.should == -2 }
    end
  end

  context "where the defender dies" do
    Given { defender.takes_damage(defender.hit_points - 1) }
    When { attacker.attack(defender, 19) }
    Then { defender.should be_dead }
  end
end

上述代码中,Invariant只在where the defender survives上下文中生效。

Jim Weirich


撰文 SegmentFault


weakish
24.6k 声望844 粉丝

a vigorously lazy deadbeat with matured immaturity