[rspec-users] Can I construct the controller myself in a controller spec?

Ben Mabey ben at benmabey.com
Thu Mar 5 10:24:27 EST 2009


David Chelimsky wrote:
> On Thu, Mar 5, 2009 at 3:31 AM, Matt Wynne <matt at mattwynne.net> wrote:
>   
>> On 5 Mar 2009, at 06:02, David Chelimsky wrote:
>>
>>     
>>> On Wed, Mar 4, 2009 at 10:38 PM, Perryn Fowler <pezlists at gmail.com> wrote:
>>>       
>>>> Hi
>>>>
>>>> I am experimenting with Constructor based dependency injection for
>>>> rails controllers.
>>>>
>>>> So I have something like this
>>>>
>>>> class LoginSessionsController < ApplicationController
>>>>
>>>>  def initialize(authenticator =  TheRealAuthenticator)
>>>>   @authenticator = authenticator
>>>>  end
>>>>
>>>>  ....
>>>> end
>>>>
>>>>
>>>> The plan was to override the authenticator used when testing with
>>>> something like
>>>>
>>>> describe LoginSessionsController.new(MyMockAuthenticator) do
>>>>  ......
>>>> end
>>>>
>>>> but rspec seems to insist on constructing the controller itself
>>>>         
>>> No, Rails insists upon constructing the controller itself. rspec-rails
>>> just wraps rails' testing framework. I'd much rather be constructing
>>> the objects myself.
>>>
>>> As for DI, there is a wealth of discussion about DI in Ruby in various
>>> user lists - general consensus is don't do it. I concur. You don't
>>> need it. You might be particularly interested in
>>> http://rubyconf2008.confreaks.com/recovering-from-enterprise.html, in
>>> which Jamis Buck, who authored a DI library for Ruby named needle,
>>> explains why that was unnecessary.
>>>       
>> That sounds a little bit like throwing the baby out with the bathwater
>> though - you still need to be able to do some kind of DI if you're doing
>> TDD, so that you can swap in a fake dependency, no? DI doesn't have to mean
>> you use some fancy framework.
>>     
>
> Agreed. I think I reacted to the term DI, about which J.B. Rainsberger
> once commented "Oh, you mean parameters." I totally agree that we need
> strategies for introducing doubles.
>
>   
>> As Pat said, this is hard when the object you want to test (in this case, a
>> Rails ActionController) is so damn awkward to instantiate in a test.
>>
>> One approach would be to change the references to @authenticator in your
>> controller to call a local #authenticator method, then override this with a
>> TestController subclass and use that subclass instead in your test.
>>
>> David, how would you suggest the OP injects his MockAuthenticator? stub out
>> Authenticator.new? I guess that's what I mostly do.
>>     
>
> That's what I usually do as well. If you think of it, in this case
> Authenticator is the factory, and you're providing a stub factory with
> this approach - something that would require more elaborate measures
> in other languages.
>
> Maybe we should make this easier by providing some facility in the
> mock framework to express the following in one statement:
>
> @authenticator = stub('authenticator')
> Authenticator.stub!(:new).and_return(@authenticator)
>
> Sure, you could make that a one liner:
>
> Authenticator.stub!(:new).and_return(@authenticator = stub('authenticator')
>
> But I mean something like:
>
> @authenticator = Authenticator.stub!
>
> I don't think *that* is the answer - but something that concise would be nice.
>
> Thoughts?
>
> David
>
>   
I like the conciseness, but it isn't very clear what it is doing IMO.  
Perhaps something a little more intention-revealing like:

@authenticator = Authenticator.stub_new!

-Ben



More information about the rspec-users mailing list