RSpec-0.8.0 Released 43

Posted by David Chelimsky Wed, 28 Feb 2007 19:39:00 GMT

We finally released RSpec-0.8.0 today. Check out the rspec website for details.

Happy Spec’ing!

sinking castles 49

Posted by David Chelimsky Wed, 31 Jan 2007 23:54:11 GMT

I recently heard it suggested that large scale software projects should be built 3 times before releasing them:
  • once to prototype
  • once to prove out design
  • once with the intent of release.

Today I heard this quote from Monty Python:

“I built a castle in the swamp and it sunk. I built a second castle and it sunk too. I built a third castle and it burned down and then sunk. But the fourth castle, Ahhhh! That one stood.”

Maybe they were on to something…

Separating setup from specify 227

Posted by David Chelimsky Sun, 14 Jan 2007 05:58:00 GMT

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.

Why play a scale when you could be playing a tune? 37

Posted by David Chelimsky Fri, 05 Jan 2007 05:21:35 GMT

Many years ago I read an interview with Pat Metheny in which the interviewer asked him about how he approaches practicing scales. This is from memory from a long time ago, so forgive any misquotes (and if anyone can help me find the text of the interview I’ll be glad to update this post), but he responded with something like “Scales are an important part of improvising and there are elements of scales in everything we play. But practicing scales by themselves isn’t that interesting. Why would you want to play a scale when you could be playing a tune?”

I’ve heard other musicians talk about this in terms of “if you practice scales you’ll play scales on the gig”. I believe this to be true, and can be found manifested in the music of many who like to call themselves jazz musicians.

That always resonated with me as an aspiring musician, and has manifested itself within my sensibilities about software as craft. This relates to why I’ve latched on to BDD and the surrounding conversation.

Focusing on internal state and structure in your tests is like practicing scales. The end result is often code that is clean in a vacuum, but doesn’t express its intent well – just like hearing that guitar player running scales up and down (again). It may use the most theoretically efficient techniques, but it fails to tell a story.

Focusing on observable behaviour in your tests is like practicing melodies. The result is that your code is more likely to express its intent. It’s more likely to be just the right code for that particular requirement. Just like the improvisor who always plays exactly the right thing for that moment.

Moisten up your tests a little 39

Posted by David Chelimsky Fri, 05 Jan 2007 04:36:00 GMT

DRY (Don’t Repeat Yourself) is a very useful guideline. As with all principles, however, there is a tendency to apply it as a golden rule without really thinking about why it is meaningful, and therefore not understanding when it is important to use and when it is not.

There is another principle that sometimes conflicts with DRY: Clean Code!

For example, look at these two specs and think about which is cleaner and easier to understand:


specify "user should supply name when registering" do
  @user = User.new(:name => "David")
  @registry.should_receive(:user_name).with("David")
  @user.register(@registry)
end


specify "user should supply name when registering" do
  @name = "David" 
  @user = User.new(:name => @name)
  @registry.should_receive(:user_name).with(@name)
  @user.register(@registry)
end

For me, the first one is simpler. No question. There’s one less line of code (that’s 25% in this case), I can clearly see the name and I don’t have to mentally decode the meaning of @name – nor do I need to look around to see where else it might be used. Remember, temporary variables are a code smell too.

The reason that I believe DRY to be important is that when you have duplicated code you run the risk of changing it in one place and forgetting to change it in another. If you do that, you’re likely to introduce bugs. That is the real risk – not the fact that you might have to type things more than once.

You could make the argument that the second example above manifests this risk. So in that case, you have to weigh clarity and DRYness and make a choice. I’ll usually choose clarity in tests.

There are other examples in which I really don’t think this risk is real. One is multiple calls to a no-arg method. This came up in an email thread on the rspec-users mailing list. The poster was looking for a way to avoid writing a line of code that logs in a user in many different rspec contexts.

The line to avoid was …


session[:logged_in] = true

... and I recommended including a module …


module LogIn
  def log_in
    session[:logged_in] = true
  end
end

context "Given a logged in user..." do
  include LogIn
  setup do
    log_in
  end
  ...
end

The poster responded that he was concerned that there is still duplication because you have to type the two statements in every context.

I see a difference between duplicated statements and duplicated calls to a no-arg method. While typing the call to log_in may require a few extra strokes, the meaning of it will never change in different contexts. So the risks associated w/ code duplication are mitigated. In fact, the real risk is that you might change its one and only meaning, in which case you’d have to look at each case and decide if the new meaning makes sense.

That problem wouldn’t go away if you could subclass contexts. In fact, it would be more sinister because the behaviour is implicit. At least if you look at log_in in each context you have some sense of what it means.

In summary, I believe strongly that DRY is a very important principle. But it’s not the only principle and it definitely isn’t implicitly the most important principle to apply in every situation. Sometimes a little moisture can be just the thing you need to clean up your code.