Test Assumptions, Not Methods
Posted by Adam Wiggins on February 23, 2008 at 04:27 PM
Specs should test assumptions, not methods.
How many specs should there be for each method? One per assumption. For example, this method:
def thumbnail_filename "images/thumbs/#{basename}.jpg" end
...has one assumption, so it needs one spec:
it "stores thumbnail jpegs in the thumbs subdir" do @image.should_receive(:basename).and_return("test") @image.thumbnail_filename.should == "images/thumbs/test.jpg" end
But this method:
def popular? !archived? and recent_views > 50 end
...has three assumptions:
it "is never considered popular when archived" do @item.should_receive(:archived?).and_return(true) @item.should_receive(:recent_views).and_return(9999999) @item.should_not be_popular end it "is not considered popular when there are not many recent views" do @item.should_receive(:archived?).and_return(false) @item.should_receive(:recent_views).and_return(1) @item.should_not be_popular end it "is considered popular when there are lots of recent views" do @item.should_receive(:archived?).and_return(false) @item.should_receive(:recent_views).and_return(1000) @item.should be_popular end
Comments
There are 4 comments on this post. Post yours →
I'm not immediately recognizing this mock syntax. You're using some kind of mock library for @item, yes? It's probably worth adding a quick toss-off line to indicate what lib the syntax is from :-)
I figured it out, at least well enough to understand, but it put me off at first.
Then again, I'm home very sick right now, so maybe this would have been obvious if my brain were at full capacity. Also, hello! I played Blood Dusk MUD long ago, which doesn't mean you'll remember me :-) Pleased to see you're doing something so cool with your time.
The mocks and "it" blocks appear to be standard Rspec syntax.
Not to nitpick too much, but to better show the intent of the tests, you should probably use stubs. Not to mention it fits with the one assert/should per test idea.
I think stubs are an inferior choice here (and in most cases) because they can fall out of date without raising an error.
For example, let's say we did @image.stub!(:basename).andreturn("test") instead of shouldreceive. If later the basename method was renamed, calling @image.thumbnail_filename within the spec would call the new method, which of course is not stubbed or mocked. The spec will most likely fail, but it will be hard to tell why. Whereas with a mock, the message makes it crystal clear: "basename should have been called but was called 0 times"
Post a comment
Required fields in bold.