HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyrailsModerate

Unit-testing a controller in Ruby on Rails

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
controllerrailstestingrubyunit

Problem

I intend this to be a general question on writing an effective set of test cases for a controller action.

I include the following ingredients:

  • Ruby on Rails



  • RSpec: A testing framework. I considered doing a vanilla Rails question, but I personally use RSpec, and I feel many other folks do too. The principles that come out of this discussion should be portable to other testing frameworks, though.



  • Will Paginate: I include this to provide an example of code whose implementation is blackboxed to the controller. This is an extreme example of just using the model methods like @programs = Program.all. I chose to go this route to incorporate an additional factor for discussion, and to demonstrate that the same principles apply whether using external application code (e.g., model code) or an external plugin.



There seems to be a lack, given my humble Google Fu, of style guides for RSpec testing at this level, so it is my hope that, on top of me improving my code, this can become a useful guide for my fellow travelers.

For example purposes, let's say I currently have in my controller the following:

class ProgramssController  params[:page], :per_page => params[:per_page] || 30
  end
end



Sidebar: For those unfamiliar with will_paginate, it tacks onto a ActiveRecord Relation (all, first, count, to_a are other examples of such methods) and delivers a paginated result set of class WillPaginate::Collection, which basically behaves like an array with a few helpful member methods.

What are the effective tests I should run in this situation? Using RSpec, this is what I've conceived at the moment:

```
describe ProgramsController do
def mock_program(stubs={})
@mock_program ||= mock_unique_program(stubs)
end

def mock_unique_program(stubs={})
mock_model(Program).as_null_object.tap do |program|
program.stub(stubs) unless stubs.empty?
end
end

describe "GET index" do
it "assigns @programs" do
Program.stub(:paginat

Solution

You forgot to test what view should be rendered. If you use this, your specs will be much cleaner. The last four should be standard matchers. See this as an example.

describe ProgramsController do
  let(:programs) { [mock_model(Program)] }    

  describe "GET index" do
    it { should paginate(Program).with_default_per_page(30) }

    describe "after pagination" do
      before(:each) do
        Program.stub(:paginate).and_return(programs)    
        get :index
      end

      it { should assign_to(:programs).with(programs) }
      it { should respond_with(:success) }
      it { should render_template(:index) }
      it { should_not set_the_flash } 
    end
  end
end

Code Snippets

describe ProgramsController do
  let(:programs) { [mock_model(Program)] }    

  describe "GET index" do
    it { should paginate(Program).with_default_per_page(30) }

    describe "after pagination" do
      before(:each) do
        Program.stub(:paginate).and_return(programs)    
        get :index
      end

      it { should assign_to(:programs).with(programs) }
      it { should respond_with(:success) }
      it { should render_template(:index) }
      it { should_not set_the_flash } 
    end
  end
end

Context

StackExchange Code Review Q#505, answer score: 19

Revisions (0)

No revisions yet.