[rspec-users] Mixing in spec helper methods

Ben Mabey ben at benmabey.com
Wed Nov 12 16:38:08 EST 2008


Nick Hoffman wrote:
> On 2008-11-11, at 19:31, Ben Mabey wrote:
>> Nick Hoffman wrote:
>>> I've written a module for my specs that contains a helper method, 
>>> and am mixing the module into my specs with #include . It seems that 
>>> the method must be called with an #it block. If it isn't, this error 
>>> occurs:
>>>
>>> ... in `method_missing': undefined method 
>>> `it_should_behave_like_an_action_that_sets_the_flash_notice' for 
>>> Spec::Rails::Example::ControllerExampleGroup::Subclass_1:Class 
>>> (NoMethodError) from ./spec/controllers/properties_controller_spec.rb:8
>>>
>>> Is there a way to call my helper method from outside of an #it 
>>> block? Here's the code:
>>> http://pastie.org/312680
>>>
>>> Thanks!
>>> Nick
>>> _______________________________________________
>>> rspec-users mailing list
>>> rspec-users at rubyforge.org
>>> http://rubyforge.org/mailman/listinfo/rspec-users
>> It looks like you want those methods in your module as class method, 
>> not instance methods.  Try extending, not including, your module 
>> (extend AuthSpecHelpers.)  You might want to read my post about 
>> creating rspec macros as well:
>> http://www.benmabey.com/2008/06/08/writing-macros-in-rspec/
>>
>> -Ben
>
> After digesting that post again, especially the contents of 
> #self.included , I noticed that one could alternatively do this:
>
> module AssignMacro
>   def self.extended(receiver)
>     receiver.extend ExampleGroupMethods
>     receiver.send :include, ExampleMethods
>   end
> end
>
> describe UserPhotosController do
>   describe "GET 'users/1/photos/2'" do
>     extend AssignMacro
>     # ...
>   end
> end
>
> Is one approach more preferable? Or should one do this so that both 
> "include AssignMacro" and "extend AssignMacro" give the same, desired, 
> result?:
>
> module AssignMacro
>   def self.included(receiver)
>     receiver.extend ExampleGroupMethods
>     receiver.send :include, ExampleMethods
>   end
>
>   class << self
>     alias_method :extended, :included
>   end
> end
>
> Thanks for your input, guys.
> -Nick
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

Some people would say that using the included or extended module hooks 
like that are evil.[1]  That said it is a very common ruby idiom even if 
it is bad.  If you are going to use the evil idiom then I would suggest 
using include and not extend since it is the idiom.  :)

Another way to do it that wouldn't take advantage of the evil hooks 
would be:

describe UserPhotosController do
  describe "GET 'users/1/photos/2'" do
    extend AssignMacro::ExampleGroupMethods
    include AssignMacro::ExampleMethods
    # ...
  end

Of course that is somewhat annoying to type everywhere.  So perhaps you 
could add another example group method that would mix in macors.. likes so:

describe UserPhotosController do
  describe "GET 'users/1/photos/2'" do
    use_macro AssignMacro
    # ...
  end
end

The 'use_maco' would be a module that you mix in onto all rspec's 
example group methods that would simply include and extend the given 
module's ExampleMethods and ExampleGroupMethods modules respectively.

The 'use_macro' is probably more clear than the hooks.  Just a thought.

-Ben


1. http://olabini.com/blog/2008/09/evil-hook-methods/



More information about the rspec-users mailing list