[rspec-users] Collection proxies need to be stubbed ?

David Chelimsky dchelimsky at gmail.com
Sun Jan 21 06:37:59 EST 2007


On 1/20/07, Francois Beausoleil <francois.beausoleil at gmail.com> wrote:
> Hi all !
>
> I just started writing specs on a new project.  I would just like to
> validate that this is the way you would write it.  I know about mocks,
> stubs and expectations.  I don't think this is a problem for me.
>
> My question really boils down to:
>
> def index
>   @projects = current_user.projects.active
> end
>
> My spec needs to return the proxy, no ?  Here's my code:
>
> context "A logged in user visiting the index action" do
>   controller_name :dashboard
>
>   setup do
>     @user = mock("user")
>     controller.stub!(:current_user).and_return(@user)
>
>     @user.should_receive(:projects).and_return(projects_proxy = Object.new)
>     projects_proxy.should_receive(:active).and_return([:a, :b])
>     get :index
>   end
>
>   specify "should have a list of projects available" do
>     assigns[:projects].should == [:a, :b]
>   end
>
>   specify "should render the index view" do
>     controller.should_render :template => "dashboard/index"
>   end
>
>   specify "should be a successful call" do
>     response.should_be_success
>   end
> end

I would approach this quite differently. The first difference being I
would have started with a spec, letting the spec help me to discover
the interface that I want on User.

context "A logged in user visiting the index action" do
  controller_name :dashboard

  setup do
    @user = mock("user")
    controller.stub!(:current_user).and_return(@user)
    @user.should_receive(:active_projects).and_return([:a, :b])

    get :index
  end

  specify "should have a list of projects available" do
    assigns[:projects].should == [:a, :b]
  end

  specify "should render the index view" do
    response.should_render :template => "dashboard/index"
  end

  specify "should be a successful call" do
    response.should_be_success
  end
end

This would lead me to this implementation ...

def index
  @projects = current_user.active_projects
end

... which would, in turn, lead me to spec out a method named
active_projects on User.

The other thing that I've been doing lately is making an effort to
separate out the noise (in setup) from the interesting bits in each
specification. I do that by using stub! in setup and should_receive in
specify, using should_receive to override stub! when appropriate. This
leads to a more verbose spec, but it makes each specify block complete
(so you don't have to look back at setup).

context "A logged in user visiting the index action" do
  controller_name :dashboard

  setup do
    @user = mock("user")
    @user.stub!(:active_projects).and_return([])
    controller.stub!(:current_user).and_return(@user)
  end

  specify "should have a list of projects available" do
    #given
    @user.should_receive(:active_projects).and_return([:a, :b])

    #when
    get :index

    #then
    assigns[:projects].should == [:a, :b]
  end

  specify "should render the index view" do
    #given - nothing unusual

    #when
    get :index

    #then
    response.should_be_success
    response.should_render :template => "dashboard/index"
  end
end

Here I've identified in each spec the Given/When/Then with comments.
Note that I abhor comments like this in production code, but I've come
to view specs as different from code. The result is that each spec is
easy to read and understand in isolation. You don't have to look up at
setup to understand a problem.

Note also that I've used two expectations in one spec. For me, having
a separate spec for should_be_success is not that meaningful when
we're spec'ing the template. From a developer standpoint it might be
helpful to have the statement there when trying to understand a
problem, but from the outside we know it was successful if the right
template shows up, no?

A little more than 2 cents. Hope this is all helpful.

Cheers,
David


>
> Thanks !
> --
> François Beausoleil
> http://blog.teksol.info/
> http://piston.rubyforge.org/
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users


More information about the rspec-users mailing list