patternrubyrailsModerate
Unit-testing a controller in Ruby on Rails
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:
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:
Sidebar: For those unfamiliar with
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
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
endSidebar: 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
endCode 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
endContext
StackExchange Code Review Q#505, answer score: 19
Revisions (0)
No revisions yet.