berkes
berkes

Reputation: 27553

Dynamically test each method in a controller

I have an Ruby on Rails 3 admin_controller with the default set of CRUD, index and so on methods. I'd like to test each of these for certain assertions with rspec.

Like response.should render_template("layouts/some_layout") or tests that it should require login.

Copy-pasting that test into the group of tests for each method is a lot of duplication. IMO it makes little sense to have an

it 'should require login' do

Duplicated several times troughout that test.

Is there a simple way to run a test on a list of methods? Say defined_methods.each do |method| it 'should' .... of some sort?

Is this a good way in the first place? Or am I taking a wrong route in the first place?

Upvotes: 2

Views: 372

Answers (3)

idlefingers
idlefingers

Reputation: 32037

If you wanted to go down the route of iteratively testing each public method in the controller, you could do something like:

SomeController.public_instance_methods(false).each do |method|
  it "should do something"
end

However, I think a shared example group (see about half way down this page: http://rspec.info/documentation/) would be prettier. If it were extracted so it could be used across all your controller specs, it'll be even nicer..

shared_examples_for "admin actions" do
  it "should require login"
end

Then in each controller spec:

describe SomeController do
  it_should_behave_like "admin actions"
end

Upvotes: 1

mfilej
mfilej

Reputation: 101

Given that you really want all those assertions, have you considered shared example groups?

shared_examples_for "an action that requires authentication" do
  it "should render successfuly" do
    sign_in(user)
    response.should be_success # or whatever
  end

  it "should deny access" do
    # don't sign_in the user
    # assert access was denied
  end
end

shared_examples_for "another behaviour" do
  # ...
end

let(:user) { create_user }

describe "#index" do
  before(:each) { get :index }
  it_behaves_like "an action that requires authentication"
  it_behaves_like "another behaviour"
end

describe "#show" do
  before(:each) { get :show }
  it_behaves_like "an action that requires authentication"
end

# ...

Of course before writing large number of specs for a basic functionality you should always check if it isn't already tested by the library that is providing the functionality (e.g. checking for the rendered template, if it is handled by rails's implicit rendering, might be a bit overkill).

Upvotes: 2

jschorr
jschorr

Reputation: 3054

Just add it to your test_helper.rb, something like:

def requires_login ... end

Upvotes: 0

Related Questions