Stubbing before_filters

21 views
Skip to first unread message

Curran Schiefelbein

unread,
Oct 28, 2009, 10:12:47 AM10/28/09
to mocha-d...@googlegroups.com
Hi,

Suppose you wanted to stub a before_filter to fail, so that you could make sure the controller action was never executed.

(This whole scenario is screaming "refactor" to me, but it comes right out of AuthenticatedSystem, so I'm trying to work with it.)

The filter method lives in a mixin, AuthenticatedSystem:

    def login_required
      logged_in? && authorized? ? true : access_denied
    end

The method I want to stub is access_denied. Under older version of Rails, the following would have worked (or so I'm told, I came to the party after 2.3 came out):

    @controller.stubs(:access_denied => false)

But nowadays, a filter has to actually invoke render or redirect to stop the filter chain.

The point of stubbing access_denied() is so that in the verification phase, I can make sure it was invoked (proving that current_user wasn't authorized). Wrote a nice little shoulda macro and everything to clean up my functional tests, then got stymied when create() was invoked anyway.

Is there a simple way to set this up? I've tried the following but it gets tangled up in a nil somewhere deep in the controller:

    @controller.stubs(:access_denied => @controller.send(:render, :text => "nuts to you"))
 
It feels dirty anyway what with using send(). Is there a Better Way to go about this? I'm not keen on stubbing the subject under test (@controller), either, but as it's only a mixed-in method, my intentions are still pure. ;)

Curran

Murray Steele

unread,
Oct 28, 2009, 1:20:30 PM10/28/09
to mocha-d...@googlegroups.com
2009/10/28 Curran Schiefelbein <c.schie...@gmail.com>:
> Hi,
>
> Suppose you wanted to stub a before_filter to fail, so that you could make
> sure the controller action was never executed.
>
> (This whole scenario is screaming "refactor" to me, but it comes right out
> of AuthenticatedSystem, so I'm trying to work with it.)
>
> The filter method lives in a mixin, AuthenticatedSystem:
>
>     def login_required
>       logged_in? && authorized? ? true : access_denied
>     end
>

Could you just stub one of the things that wil cause login_required to
call access_denied? E.g. just stub logged_in? or authorized? to return
false.

It feels weird because you are stubbing at a level lower than the
filter, but it's at least a stubbing at a level higher than forcing a
render.

Curran Schiefelbein

unread,
Oct 28, 2009, 3:13:05 PM10/28/09
to mocha-d...@googlegroups.com
Well, I was trying to write a test for authorized?'s correct functioning, so stubbing it would sidestep the test.

I can't just call authorized? to check its return value, because it relies on the value of session[:user], and that's nil until a controller action is attempted. (Logging in sets the session variable in the request, not the controller.)

Curran

Murray Steele

unread,
Oct 29, 2009, 5:16:26 AM10/29/09
to mocha-d...@googlegroups.com
2009/10/28 Curran Schiefelbein <c.schie...@gmail.com>:

> Well, I was trying to write a test for authorized?'s correct functioning, so
> stubbing it would sidestep the test.

Urrr. yeah. Sorry.

> I can't just call authorized? to check its return value, because it relies
> on the value of session[:user], and that's nil until a controller action is
> attempted. (Logging in sets the session variable in the request, not the
> controller.)

As penance for my earlier stupidity, here's a suggestion that might
actually be useful. I assume that access_denied either redirects you
to a login, renders a 403 or renders some other template. Could you
assert that those things have happened instead of expecting
access_denied itself has been called?

Murray

Curran Schiefelbein

unread,
Oct 29, 2009, 8:41:19 PM10/29/09
to mocha-d...@googlegroups.com
Oh yes, that's what I had done originally. Then I tried to "clean it up" a bit, reduce LOC. Now I'm just mildly obsessed with whether it's possible! :)

Curran

Duncan Beevers

unread,
Jan 20, 2010, 1:41:58 PM1/20/10
to mocha-d...@googlegroups.com
I just ran into this situation today and came up with a solution I'm pretty happy with.

Another way to halt Rails' filter chain is to raise an error, so instead of setting an expectation on the filter method, I rigged it to explode when called.

module RestrictionTestHelper
  class AdminOnlySatisfied < StandardError; end
 
  def assert_admin_only action
    @controller.stubs(:authenticated_only).returns(true)
    @controller.stubs(:admin_only).raises(AdminOnlySatisfied)
    assert_raise AdminOnlySatisfied do
      get action
    end
  end
end

ActionController::TestCase.send(:include, RestrictionTestHelper)


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "mocha-developer" group.
To post to this group, send email to mocha-d...@googlegroups.com
To unsubscribe from this group, send email to mocha-develop...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mocha-developer?hl=en
-~----------~----~----~----~------~----~------~--~---


Curran Schiefelbein

unread,
Jan 21, 2010, 3:57:47 PM1/21/10
to mocha-d...@googlegroups.com
Cool, I didn't know you could stub a method to raise an exception. That solves it for me too!

Thanks,
Curran

--
You received this message because you are subscribed to the Google Groups "mocha-developer" group.
To post to this group, send email to mocha-d...@googlegroups.com.
To unsubscribe from this group, send email to mocha-develop...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/mocha-developer?hl=en.


Curran Schiefelbein

unread,
Mar 19, 2010, 12:36:48 PM3/19/10
to mocha-d...@googlegroups.com
I just came across this juicy little example:
http://blog.jayfields.com/2006/12/ruby-alias-method-alternative.html

It explains how to do what I was trying to do originally, i.e.
redefine access_denied() to invoke render, as it would do when a user
is actually denied access. Then the test can expect() normal behavior
rather than artificial (raised exception).

For future reference :)

Curran

Reply all
Reply to author
Forward
0 new messages