Topic: How to test before_filter?


I've added "before_filter :require_login" to my application controller. How can I test that "require_login" method is executed for all/specific actions in a particular controller?

I've already figured out that I can get all actions of the controller using "@controller.public_instance_methods(false)", but I don't know how to verify that the "require_login" method is executed before the proper action.

Thank you in advance

Re: How to test before_filter?

The easiest way would be to make your require_login set an instance variable called @require_login_called or something like that and test for the existence of it in your tests (@controller.get_instance_variable("@require_login_called")).

But a much cleaner solution would be to not test for whether the method was called but whether logged-out users can access the controller.  Because what you're really trying to test is whether certain users can visit certain pages, right?  So just check for that.  Then you can change the implementation (rename or replace the before filter) later and your tests won't break.

Re: How to test before_filter?


I'll go with the cleaner approach, as actually you're right that it will be enough in my case.

Re: How to test before_filter?

I have a related question. I have three user "levels" in my application: normal, editor, and admin. The editors and admin have the ability to create/update/destroy certain models. A before_filter checks this access level before each of those methods (also new and edit).

So do I need to write four tests for each controller method (one for each access level plus one for unauthenticated users)? This ends up being a lot of code. If this is the correct way to write the tests, how do I keep it DRY?

Re: How to test before_filter?

If you're using rSpec, you can do this:

describe AccountsController, "as guest," do

  %w[index show edit update destroy].each do |action|
    it "#{action} should redirect to login with error" do
      get action
      flash[:error].should_not be_nil
      response.should redirect_to(login_path)

You can probably do something similar with test/unit where you would just generate methods in that loop instead.

That is acceptable for really simple authorization techniques, but if you have three levels of users then you probably have some more complex logic behind the scenes. Instead what I recommend doing is having the before filter delegate the logic to something else and test that in isolation. I can't really go into detail because it relies heavily on the specifics of your authorization.

Railscasts - Free Ruby on Rails Screencasts

Re: How to test before_filter?

ryanb wrote:

Instead what I recommend doing is having the before filter delegate the logic to something else and test that in isolation.

I like this idea. Basically my before_filter is running a private method (must_be_admin_or_editor) in application.rb which redirects elsewhere if the user is not an admin or editor.

But how do I test this method? Can I call it directly? I need to set a user in a session, then assert that nothing happens or that a specific redirect happens.

BTW, I'm not using RSpec yet. The number of plugins/extensions/etc. to Rails is incredible and I'm trying to limit my exposure to them in order to concentrate on getting good at the basics.