Separating setup from specify 2
In his blog on web GUI testing, Uncle Bob presents an example using RSpec.
There are a couple of things that I’ve begun to approach a bit differently, and I’d like to present them for your consideration and comment.
In my previous posts on blogs and email lists, etc, I’ve talked about using setup as the context in which each spec is run. The problem that I’ve come to recognize is that there are often so many variables in contexts that things can quickly get quite confusing.
So rather than using setup as the context, I’ve begun to use setup to take care of what NEEDS to happen in order for the specs to be able to run, but have each specify block tell a complete story, including its own context (i.e. Givens).
To accomplish this, I like to stub methods in setup and reserve should_receive for expectations within the specs themselves. Of late, I’ve also been commenting the specs to clarify the Given/When/Then in each spec. Given/When/Then is conceptually the same as Build/Operate/Check, but with slightly different words chosen to be a little more customer friendly:
Given preconditions When action Then outcome
Mock expectations become part of the Givens. This takes a minute to get used to, but becomes quite natural.
The specs end up far more verbose, but they are VERY clear and more true to the BDD triad of Given/When/Then. Here’s the example with the triad commented. I’m curious to hear what you think about it:
context "Given a request to render message/list with one message the page" do
setup do
@message = mock "message"
@caller = mock "person",:null_object=>true
@school = mock "school"
@message.stub!(:school).and_return(school)
@message.stub!(:time).and_return(Time.parse("12/31/06"))
@message.stub!(:caller).and_return(@caller)
@message.stub!(:iep).and_return(true)
@caller.stub!(:first_name).and_return("first")
@caller.stub!(:last_name).and_return("second")
@school.stub!(:name).and_return("school name")
assigns[:messages]=[m]
assigns[:message_pages] = mock "message_pages", :null_object=>true
end
specify "should show the time" do
#given
@message.should_receive(:time).and_return(Time.parse("1/5/07"))
#when
render 'message/list'
#then
response.should_have_tag :td, :content=>"12:00 AM 1/5", :attributes=>{:id=>"time"}
end
specify "should show caller first and last name" do
#given
@caller. should_receive(:first_name).and_return("Bob")
@caller. should_receive(:last_name).and_return("Martin")
#when
render 'message/list'
#then
response.should_have_tag :td, :content=>"Bob Martin", :attributes=>{:id=>"caller"}
end
specify "should show school name" do
#given
@school. should_receive(:name).and_return("Jefferson")
#when
render 'message/list'
#then
response.should_have_tag :td, :content=>"Jefferson", :attributes=>{:id=>"school"}
end
specify "should show X in the IEP field when IEP is true" do
#given
@message.should_receive(:iep).and_return(true)
#when
render 'message/list'
#then
response.should_have_tag :td, :content=>"X",:attributes=>{:id=>"iep"}
end
specify "should show nothing in the IEP field when IEP is false" do
#given
@message.should_receive(:iep).and_return(false)
#when
render 'message/list'
#then
response.should_have_tag :td, :content=>"",:attributes=>{:id=>"iep"}
end
end
As I noted above, the specs become more verbose and even bear some duplication. As you may know, I have much less trouble with duplication in specs than I do with duplication in the code being specified.
Thoughts and comments are welcome.

I was skeptical of BDD at first. My initial reaction was that it was just a small change to the syntax of the standard XUnit form; and so wasn’t really significant.
However, havng used rspec for a few weeks I realized that the difference in form was changing the way I viewed the tests in a non-trivial manner. The more I wrote tests in the BDD form, the more I wanted them to read like specs.
Making tests read like specs requires that you change the form of those tests much more than the simple syntax shift from XUnit would imply. I found myself breaking my tests up into many smaller contexts with isolated scenarios. I found myself describing those scenarios in setup and asserting their results in specs. I found myself struggling to phrase the specs in a more and more declarative fashion.
This exerience has made me much less skeptical that subtle shifts in syntax can have significant effects on structure. So I will try the Given/When/Then approach and see what happens.
Hmm, this is pretty interesting. Like Uncle Bob, I’d like to experiment with it. Initially, I was bothered with all the “waste†in the setup. Now, I see what you are doing, but I was confused at first because none of the stub values were actually used in verification. I get the NEED part now in the setup.
In this specific case, you’re checking a small part of a single method call in each spec. That is, did this one collaborating object get called correctly and is this one piece in the result. That’s what’s new to me. I’d like to see how you’d do Given/When/Then for a more object-state-focused case rather than this more result-of-a-method-call-focused case. Perhaps you could show the spec for a Stack – from your previous blog entry.