-
Notifications
You must be signed in to change notification settings - Fork 61
Tutorial: invariants
This is part of the RSpec/Given Tutorial.
Invariants are specification assertions that are evaluated just before each Then in scope. This allows us to specify that something is true across a range of tests without repeating the assertion at every point.
A simple example of might be the definition of the "dead?" method on a character. A character will be considered dead if their energy level drops below zero. We capture that definition at the top level of the spec, assuring that the truth of that assertion is verify at every Then clause in scope.
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
Sometimes we just wish to assert some is true across a subset of all specifications. We can do that by putting the Invariant clause in a nested describe/context block.
Imagine that we break up our attack and damage specification into two sections, one where the defender survives and one where the defender dies.
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
-- Previous: Tutorial: Inherited when