Ruby Forum RSpec > Spec the Application Controller application.rb

Posted by Andy Croll (andycroll)
on 21.04.2008 17:27
How would I go about writing specs for methods in the Application
Controller:

I'm thinking of simple methods that do authentication, through before
filters or for example how might I spec this method in an
application_spec.rb?

  def store_location
    session[:return_to] = request.request_uri
  end

The trouble is I'm not generating a request object as the methods are to
be used by all controllers... I've tried stubbing...

request = mock_model(URI::HTTP, :request_uri => "something")

...or setting the variable in the spec itself...

request.response_uri = "something"

...but I can't seem to get the approach right!
Posted by Pat Maddox (pergesu)
on 21.04.2008 23:09
(Received via mailing list)
On Mon, Apr 21, 2008 at 8:27 AM, Andy Croll <lists@ruby-forum.com> 
wrote:
>
>  The trouble is I'm not generating a request object as the methods are to
>  be used by all controllers... I've tried stubbing...
>
>  request = mock_model(URI::HTTP, :request_uri => "something")
>
>  ...or setting the variable in the spec itself...
>
>  request.response_uri = "something"
>
>  ...but I can't seem to get the approach right!

Hey Andy,

You can define a controller method on the fly in order to test this
out.  I just did a quick experiment to demonstrate it...obviously
modify to suit your needs.

application_controller_spec.rb:
require File.dirname(__FILE__) + '/../spec_helper'

describe "a before_filter" do
  class FooController < ApplicationController
    def index; render :text => "foos"; end
  end
  controller_name :foo

  it "should work" do
    get :index
    assigns[:assigned].should_not be_blank
  end
end

application.rb:
class ApplicationController < ActionController::Base
  before_filter :set_assigned

  def set_assigned
    @assigned = "yay"
  end
end
Posted by Andy Croll (andycroll)
on 23.04.2008 08:19
Pat Maddox wrote:
> You can define a controller method on the fly in order to test this
> out.  I just did a quick experiment to demonstrate it...obviously
> modify to suit your needs.

Thanks Pat.

I think I'm confusing two issues.

1) How to test before filters for something like authentication
2) How to test functions provided in the application controller

I'm not putting the before filter in the application.rb, I'm likely to 
be using it to protect various actions in the app.

Is there a way to to call methods directly within the application.rb, 
spec them there and then sub for functionality in the other controllers?

Andy

PS Your 'controller spec' blog post was the 'light-going-on-in-my-head' 
moment for RSpec. Thanks for that!
Posted by Pat Maddox (pergesu)
on 23.04.2008 08:39
(Received via mailing list)
On Tue, Apr 22, 2008 at 11:19 PM, Andy Croll <lists@ruby-forum.com> 
wrote:
>  2) How to test functions provided in the application controller
>
>  I'm not putting the before filter in the application.rb, I'm likely to
>  be using it to protect various actions in the app.

You can still use the technique that I showed, you would just call
before_filter in the fake controller.  That would allow you to specify
and implement the filter in isolation.

>  Is there a way to to call methods directly within the application.rb,
>  spec them there and then sub for functionality in the other
>  controllers?

No to the first part, unfortunately.  Rails' controller design isn't
particularly test-friendly.

As far as using them in other controllers, you can just use the real
filter implementation if you want, or stub them if you prefer.

Pat
Posted by Andy Croll (andycroll)
on 24.04.2008 05:16
Pat Maddox wrote:

> You can still use the technique that I showed, you would just call
> before_filter in the fake controller.  That would allow you to specify
> and implement the filter in isolation.

Aha! Success, although I needed to add in a little Route fixing to make 
it work.

application_spec.rb:

describe ApplicationController, "storing locations" do
  class FooController < ApplicationController
    before_filter :assign_var
    def index; render :text => "foos"; end
  end
  controller_name :foo

  before(:each) do
    ActionController::Routing::Routes.draw do |map|
      map.resources :foo
    end
  end

  it "should assign the current user" do
    get :index
    assigns[:var].should_not be_blank
  end
end

application.rb:

class ApplicationController < ActionController::Base
  def assign_var
    @var = "Quantum Leap Rocks"
  end
end

Hooray.
Posted by Andy Croll (andycroll)
on 24.04.2008 08:20
This bit however, replaces your other routes, so you cannot use them in 
your tests

>   before(:each) do
>     ActionController::Routing::Routes.draw do |map|
>       map.resources :foo
>     end
>   end

Is there a sensible way to append to the routes.rb that I'm missing?

Andy
Posted by Zach Dennis (Guest)
on 25.04.2008 22:26
(Received via mailing list)
Do this...

  after do
    eval IO.read(RAILS_ROOT + "/config/routes.rb")
  end

Zach