Sign up ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

In my project (https://github.com/GCorbel/comment-my-projects) I have this kind of code to test my controllers.

#encoding=utf-8
require 'spec_helper'

describe ProjectsController do
  let!(:project) { build_stubbed(:project, user: user) }
  let(:user) { build_stubbed(:user) }

  before(:each) { sign_in user }

  describe "GET 'index'" do
    it "render index template" do
      get 'index'
      should render_template('index')
    end
  end

  describe "GET 'show'" do
    let!(:comment) { build_stubbed(:comment) }

    before(:each) { Project.stubs(:find).returns(project) }

    it "render show template" do
      get 'show', id: project.id
      should render_template('show')
    end

    it "create a new comment" do
      Comment.expects(:new).returns(comment)
      get 'show', id: project.id
    end
  end

  describe "GET 'new'" do
    it "render new template" do
      get 'new'
      should render_template('new')
    end
  end

  describe "POST 'create'" do
    before(:each) do
      Project.stubs(:new).returns(project)
    end

    context "with valid data" do
      before(:each) { project.stubs(:save).returns(true) }

      it "redirect to project's path" do
        post 'create'
        should redirect_to(project)
      end

      it "save the project" do
        lambda do
          post 'create'
        end.should change(user.projects, :size).by(1)
      end

      it "set a flash message" do
        post 'create'
        should set_the_flash[:notice].to("Votre projet a été ajouté")
      end
    end

    context "with invalid data" do
      before(:each) { project.stubs(:save).returns(false) }

      it "render new template" do
        post 'create'
        should render_template('new')
      end
    end
  end

  describe "GET 'edit'" do
    before(:each) do
      Project.stubs(:find).returns(project)
    end

    it "render edit template" do
      get 'edit', id: project.id
      should render_template('edit')
    end
  end

  describe "POST 'update'" do
    before(:each) do
      Project.stubs(:find).returns(project)
    end

    context "when valid" do
      before(:each) { project.stubs(:update_attributes).returns(true) }

      it "redirect to project's path" do
        post 'update', id: project.id
        should redirect_to(project)
      end

      it "update the project" do
        project.expects(:update_attributes)
        post 'update', id: project.id
      end

      it "set a flash message" do
        post 'update', id: project.id
        should set_the_flash[:notice].to("Votre projet a été modifié")
      end
    end

    context "when invalid" do
      before(:each) { project.stubs(:update_attributes).returns(false) }

      it "render edit template" do
        post 'update', id: project.id
        should render_template('edit')
      end
    end
  end

  describe "DELETE 'destroy'" do
    before(:each) do
      Project.stubs(:find).returns(project)
      project.stubs(:destroy)
    end

    it "redirect to project's path" do
      delete 'destroy', id: project.id
      should redirect_to(root_path)
    end

    it "delete the project" do
      project.expects(:destroy)
      delete 'destroy', id: project.id
    end

    it "set a flash message" do
      delete 'destroy', id: project.id
      should set_the_flash[:notice].to("Votre projet a été supprimé")
    end
  end
end

I do this for :

  • Isolate my tests : I don't want to retest the model and I don't want to hit the database. It's faster.
  • Test all actions that should be do by the controller

And I have this questions :

  • Should I test the assignments or is to long for nothing?
  • How should I to stub my models? Is it better to place all stubs in a global before(:each) like this :

    ...
    before(:each) do 
      sign_in user
      Project.stubs(:find).returns(project)
      Project.stubs(:new).returns(project)
      project.stubs(:destroy)
    end
    ...
    

    it's dryer and cleaner but less efficient.

  • Should I realy isolate my tests? I tested it without stubs and I loose 10 seconds. What do you think about that?

share|improve this question

1 Answer 1

up vote 2 down vote accepted

I found this answer helpful; I also like using the shoulda matchers to clean things up.

Yes, I think you should test your assignments. If you use the shoulda matchers, this becomes much less painful, for example:

describe "POST 'update'" do

  context "when invalid" do
    before(:each) do
      project.stubs(:update_attributes).returns(false)
      post 'update', id: project.id
    end

    it { should render_template('edit') }
    it { should assign_to(:project).with(project) }
  end
end

I usually stub where it's relevant rather than at a global level, but I don't have a good argument as to why besides that it's easier for me to understand when I'm reading it.

It's fine to test in isolation as long as you're testing your full stack somewhere like with cucumber or integration tests.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.