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

David Chelimsky dchelimsky at gmail.com
Thu Mar 5 12:39:13 EST 2009


On Thu, Mar 5, 2009 at 9:24 AM, Ben Mabey <ben at benmabey.com> wrote:
> 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!

That's the right direction. Not in love with that either - especially
since it requires adding a new method to Object.

How about something like:

stub_factory(Authenticator)

This would configure Authenticator to return the same test double
every time it receives #new. So you could say:

stub_factory(Authenticator)
@authenticator = Authenticator.new

Or, perhaps:

@authenticator = stub_factory(Authenticator).new

Not there yet (that's a bit confusing), but I think you can see where
this is headed. More ideas?

David





>
> -Ben
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list