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

David Chelimsky dchelimsky at gmail.com
Thu Mar 5 09:26:01 EST 2009

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')

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.



> Matt Wynne
> http://blog.mattwynne.net
> http://www.songkick.com
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

More information about the rspec-users mailing list