[rspec-users] testing behaviour or testing code?

David Chelimsky dchelimsky at gmail.com
Fri Aug 24 09:59:25 EDT 2007

On 8/24/07, David Green <justnothing at tiscali.co.uk> wrote:
> hypothetical question for all you BDD experts:
> I want to make sure that a :list action always returns widgets in
> alphabetical order. There's at least 2 ways of doing this:
> it "should fetch items in alphabetical order" do
>   Widget.should_receive(:find).with(:order => "name ASC")
>   get :list
> end
> it "should fetch items in alphabetical order" do
>   [:red, :green, :blue].each {|x| Widget.create(:name => x) }
>   get :list
>   assigns[:widgets].first.name.should == 'blue'
>   assigns[:widgets].last.name.should == 'red'
> end
> with the first method, I get to mock the important calls and stub the rest,
> but the example is very closely tied to the implementation. If I change from
> Widget.find to Widget.find_alphabetically then the example breaks (assuming
> find_alphabetically() doesn't use AR::Base.find)
> with the second method, I'm testing the behaviour more than how it's
> implemented. I don't care what the action does as long as it gives me an
> array of widgets sorted alphabetically, but I spend more time setting things
> up and worrying about model validations. In addition, the specs are tied to
> a db.
> so which is the better method, and is there another way i havn't considered
> that gives me the best of both worlds?

It depends on how high you have your magnifying glass set. Really!

Here's how I'd get there:

In an integration test, which I use as ... well ... integration tests
(i.e. pretty close to end to end - just no browser, so the javascript
can't get tested), I'd have something akin to the second example,
except that the creates would be done through a controller. This would
be in place before I ever started working on individual objects.

Then I'd develop the view, followed by the controller, followed by the
model. Typically, in my experience, that would result in something
like (not executing these so please pardon any potential bugs):

describe "/widgets/index" do
  it "should display a list of widgets" do
    assigns[:widgets] = [
      mock_model(Widget, :name => 'foo'),
      mock_model(Widget, :name => 'bar')
    render '/widgets/index'
    response.should have_tag('ul') do
      with_tag('li', 'foo')
      with_tag('li', 'bar')

describe WidgetController, 'responding to GET /widgets' do
  it "should assign a list of widgets" do
    Widget.should_receive(:find_alphabetically).and_return(list = [])
    get :index
    assigns[:widgets].should == []

describe Widget, "class" do
  it "should provide a list of widgets sorted alphabetically" do
    Widget.should_receive(:find).with(:order => "name ASC")

You're correct that the refactoring requires you to change the
object-level examples, and that is something that would be nice to
avoid. But also keep in mind that in java and C# people refactor
things like that all the time without batting an eye, because the
tools make it a one-step activity. Refactoring is changing the design
of your *system* without changing its behaviour. That doesn't really
fly all the way down to the object level 100% of the time.



> --
> View this message in context: http://www.nabble.com/testing-behaviour-or-testing-code--tf4322619.html#a12309322
> Sent from the rspec-users mailing list archive at Nabble.com.
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

More information about the rspec-users mailing list