Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Given/When/Then keywords for RSpec Specifications

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.


rspec-given is an RSpec 2 extension to allow Given/When/Then notation in RSpec specifications. It is a natural extension of the experimental work done on the Given framework. It turns out that 90% of the Given framework can be trivially implemented on top of RSpec.

Why Given/When/Then

RSpec has done a great job of making specifications more readable for humans. However, I really like the given / when / then nature of Cucumber stories and would like to follow the same structure in my unit tests. rspec-given allows a simple given/when/then structure RSpec specifications.


rspec-given is quite usable at the moment, although is is lacking several features.

  • Invariants are not supported yet.
  • Then assertions without should are not supported yet.

Example Zero

Here's the spec that I've been playing with. Its gone through mulitple revisions and several prototype implementations. And this is probably not the final form.

With all that in mind, here's a specification in my imaginary framework:

require 'spec_helper'
require 'stack'

describe Stack do
  # NOTE: Invariants are not yet supported in rspec-given
  # Invariant { stack.depth >= 0 }
  # Invariant { stack.empty? == (stack.depth == 0) }

  Given(:an_empty_stack) { }

  Given(:a_stack_with_one_item) do do |s|

  Given(:a_stack_with_several_items) do do |s|

  context "an empty stack" do
    Given(:stack) { an_empty_stack }

    Then { stack.depth.should == 0 }

    context "Pushing onto an empty stack" do
      When { stack.push(:an_item) }

      Then { stack.depth.should == 1 }
      Then { == :an_item }

  context "a stack with one item do" do
    Given(:stack) { a_stack_with_one_item }

    context "popping an item empties the stack" do
      When(:pop_result) { stack.pop }

      Then { pop_result.should == :an_item }
      Then { stack.should be_empty }

  context "a stack with several items" do
    Given(:stack) { a_stack_with_several_items }
    Given!(:original_depth) { stack.depth }

    context "pushing a new item adds a new top" do
      When { stack.push(:new_item) }

      Then { == :new_item }
      Then { stack.depth.should == original_depth + 1 }

    context "popping an item removes the top item" do
      When(:pop_result) { stack.pop }

      Then { pop_result.should == :top_item }
      Then { == :second_item }
      Then { stack.depth.should == original_depth - 1 }

Let's talk about the individual sections.


The Given section specifies a starting point, a set of preconditions that must be true before the code under test is allowed to be run. In standard test frameworks the preconditions are established with a combination of setup methods (or :before actions in RSpec) and code in the test.

In the example code above, we see three starting points of interest. One is an empty, just freshly created stack. The next is a stack with exactly one item. The final starting point is a stack with several items.

A precondition in the form "Given(:var) {...}" creates an accessor method named "var". The accessor is lazily initialized by the code block. If you want a non-lazy given, use "Given!(:var) {...}".

A precondition in the form "Given {...}" just executes the code block for side effects. Since there is no accessor, the code block is executed immediately (i.e. no lazy evaluation).

The preconditions are run in order of definition. Nested contexts will inherit the preconditions from the enclosing context, with out preconditions running before inner preconditions.


The When block specifies the code to be tested ... oops, excuse me ... specified. After the preconditions in the given section are met, the when code block is run.

There should only be one When block for a given context.


The Then sections are the postconditions of the specification. These then conditions must be true after the code under test (the When block) is run.

The code in the Then block should be a single boolean condition that devaluates to true if the code in the When block is correct. If the Then block evaluates to false, then that is recorded as a failure.


The Invariant block is a new idea that doesn't have an analog in RSpec or Test::Unit. The invariant allows you specify things that must always be true. In the stack example, empty? is defined in term of size. Whenever size is 0, empty? should be true. Whenever size is non-zero, empty? should be false.

You can conceptually think of an Invariant block as a Then block that automatically gets added to every When within its scope.

Invariants nested within a context only apply to the When blocks in that context.

Invariants that reference a Given precondition accessor must only be used in contexts that define that accessor.

NOTE: Invariants are not yet implemented in the current version of rspec-given.


Something went wrong with that request. Please try again.