[rspec-rails] how to test module behavior once and then confirm that controllers implement it?

Hi,

I’m using rspec-rails (1.3.2), and wondering how to save myself the
trouble of testing filters for ActionControllers when those filters
call methods included from modules.

Specifically, what is the recommended structure for the test of the
module filter; next, how can I confirm that the controller classes
that have included the module and are properly calling its methods as
filters.

Cracking this could save me from duplicating the testing of the full
behavior of the filters in several instances, in several
ActionController classes.

Thanks,

Lille

Hey Lille.

Specifically, what is the recommended structure for the test of the
module filter;

How about creating a shared example group, and referencing that?
http://blog.davidchelimsky.net/2010/11/07/specifying-mixins-with-shared-example-groups-in-rspec-2/

next, how can I confirm that the controller classes
that have included the module and are properly calling its methods as
filters.

You can check if a class included a module like this:
Foo.should include Bar

When an object calls a method that was mixed in, the method’s called as
though it truly is a part of the class. So you can just do:

Module Bar
def baz; end
end

Class Foo
include Bar

def something
baz
end
end

f = Foo.new
f.should_receive(:baz).and_return nil
f.something

In the rest of your specs, it’s just a matter of stubbing out the call
to
“baz”.

Cracking this could save me from duplicating the testing of the full
behavior of the filters in several instances, in several
ActionController classes.

I hope that helps!
Nick

Thanks Nick, that was helpful.

I’m wondering if it’s possible to test module behavior and then test
that the module behavior of interest is invoked from the before/after
filter enclosing the controller action under test.

To me, it seems that I’m missing a step if I don’t fill in my 4),
below:

  1. test included module behavior
  2. test that module is included in controller class
  3. test that the module methods are responsive from the host class
  4. [test that the module method(s) invoked in before/after filters for
    actions in the host are called when their enclosed actions are.]

Maybe it would be helpful to note that my module behavior is
redirection.

Thanks,

Lille

David,

Thanks (and, yes, I consult “The RSpec Book” often).

I had familiarized myself with your reference.

I guess I depart from the BDD line, because I feel that if I test a
module and I test that the host implements it when expected, then that
should be enough. For example, if I have a module whose single method
has four possible results and then I implement it in 4 hosts, I might
have to have as much as 16 tests versus my approach’s 8,
alternatively.

Of course, it seems like testing the invocations of the module has no
facility in RSpec, due, perhaps, to the BDD approach, which, I allow,
I may come to see as wiser, with more experience.

Thanks for your helpful comments.

Lille

On Jan 15, 2011, at 9:45 AM, Lille wrote:

  1. test that module is included in controller class
  2. test that the module methods are responsive from the host class
  3. [test that the module method(s) invoked in before/after filters for
    actions in the host are called when their enclosed actions are.]

Maybe it would be helpful to note that my module behavior is
redirection.

Then that ^^ is what you want to specify!!! Not 1 or 2. Maybe
3 and/or 4, but they are expressed in very procedural/structural ways.

Paraphrasing myself from The RSpec Book: BDD is about behavior, not
structure. It is about what code does, not what code is.

In this case, the behavior is:

Given these conditions
When I visit one page
Then I should be redirected to other page

Expressed in RSpec:

describe SomeController do
describe “the action” do
context “in some context” do
post :the_action
response.should redirect_to(“other”)
end
end
end

Please give
http://blog.davidchelimsky.net/2010/11/07/specifying-mixins-with-shared-example-groups-in-rspec-2/
a read and let us know if you agree/disagree with the approach.

Cheers,
David

though it truly is a part of the class. So you can just do:
end

behavior of the filters in several instances, in several
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

Cheers,
David

On Sat, Jan 15, 2011 at 9:40 PM, Lille [email protected] wrote:

I guess I depart from the BDD line, because I feel that if I test a
module and I test that the host implements it when expected, then that
should be enough. For example, if I have a module whose single method
has four possible results and then I implement it in 4 hosts, I might
have to have as much as 16 tests versus my approach’s 8,
alternatively.

(snip)

Of course, it seems like testing the invocations of the module has no
facility in RSpec, due, perhaps, to the BDD approach, which, I allow,
I may come to see as wiser, with more experience.

RSpec provides easy access to message expectations for things like that.

In the case of a single module included in several places, I would
probably specify the behavior in one place (either directly against
the model, or using a fake wrapper if necessary), and then use a
message expectation to check that you’ve hooked everything up. E.g.:

require ‘spec_helper’

class FilterTesterController < ApplicationController

before_filter :some_filter, :only => [:wrap_some_filter]
def wrap_some_filter
# whatever
end
end

describe FilterTesterController, “#some_filter” do

before(:each) do
MyApp::Application.routes.draw do
get :wrap_some_filter, :to => ‘filter_tester#wrap_some_filter’,
:as => ‘originating’
end
end

after(:each) do
MyApp::Application.reload_routes!
end

it “does what I expect it to” do
get :wrap_some_filter
# expectation
end
end

describe “One or all of your other classes that include the module” do
it “is hooked up” do
YourModule.should_receive(:the_method).with :some_params
get :some_action # or YourClass.new.some_method or whatever
end
end

Cheers,
Katrina