[Rspec-users] *what* to test?

aslak hellesoy aslak.hellesoy at gmail.com
Sun Oct 15 17:22:43 EDT 2006


On 10/15/06, Mike Pence <mike.pence at gmail.com> wrote:
> So I dig rspec and BDD, of course. I thought that Dave's Google Video
> was a great intro () -- even if it was a bit heavy on theory and a bit
> loose on the nuts and bolts. But I don't see anyone sufficiently
> answering the big question:
>
> What do you test? How do you define higher level and lower level
> behaviors that should have tests written for them?

I'm going to be elaborate here. There is no quick answer. Here is how
I teach it:

Start by asking yourself (or better - whomever wants the software):
"what do you want to accomplish with the software".

Try to come up with simple tasks that you can do with the software and
elaborate each of those. These are called User Stories (look it up).
Here is an example of a User Story for someone who wants to play
bowling:

== See total score ==
As a player
I want to see the total score at the end of the game
So that I can compare scores with other players and my own personal record

What you see here is the Narrative of the User Story. It's not enough
to leap into BDD/TDD yet, but a good starting point. Now, write down
some Acceptance Criteria for the User Story. The purpose of Acceptance
Criteria is to help the programmers know When They Are Done. A second
(and very important role) of Acceptance Criteria is that they are the
primary input for the spec writing activity.

I recommend that Acceptance Ariteria be written in a Given-When-Then
style (GWT). Each one of them should be an example of how the software
should work. They are meant to be examples.

== Acceptance Criteria ==
The programmer will know when (s)he is done when:

Given I have a new game # Initial known state
When I throw all balls in the gutter # An action or event
Then the final score should be zero # An observable outcome

Given I have a new game
When I knock down 3 pins, then all balls in the gutter
Then the final score should be 3

Given I have a new game
When I knock down 3 pins, then 7, then 2, then all balls in the gutter
Then the final score should be 14

etc.

Try to come up with really simple acceptance criteria (examples) and
make them gradually more complex. You'll start developing specs to
satisfy the simple ones first.

Let's turn the first Acceptance Criterion (for the gutter game) into a spec:

context "An empty game" do # This is the "Given"
  specify "should give zero score when all balls go in the gutter" do
# This is the When+Then
    game = Game.new
    (1..20).each do
      game.roll(0)
    end
    game.score.should_be 0
  end
end

This is all the code you have. You haven't written the Game class yet.
The spec expresses the first GWT acceptance criterion, and as you see,
it's a fairly verbatim translation of it. When you run it you'll get
the following error:

NameError in 'An empty game should give zero score when all balls go
in the gutter'
uninitialized constant Game

Hooray. That is good. It's good because RSpec is now telling you what
to do next. You'll implement the Game class:

class Game
end

Run the spec again and see it fail with a new error message:

NoMethodError in 'An empty game should give zero score when all balls
go in the gutter'
undefined method `roll' for #<Game:0x3e85d8>

Now, define it:

class Game
  def roll(pins)
  end
end

Run the spec again:

NoMethodError in 'An empty game should give zero score when all balls
go in the gutter'
undefined method `score' for #<Game:0x3e85d8>

And fix it:

class Game
  def roll(pins)
  end

  def score
    0
  end
end

Run the spec again and see it pass. You have satisfied the first
acceptance criterion. You now have a bowling game that will correctly
calculate the score for people who always throw the balls in the
gutter.

Now you attack the next acceptance criterion.

In the real world you'll have more complex things than this of course,
but the approach can be the same. Start at the high level and drill
down. Start with something that is at the border of your system -
something that can be verified by an end user. Let the guts evolve
gradually, and let them evolve from functional user stories.

I highly recommend doing the Bowling Game Kata (from which this intro
was inspired):
http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata. It's
trivial programming, but a mind-bending excercise for those who are
unfamiliar with TDD and BDD.

Cheers,
Aslak

> _______________________________________________
> Rspec-users mailing list
> Rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the Rspec-users mailing list