Why do we need constructor injection?

189 views
Skip to first unread message

Jon Kruger

unread,
Sep 25, 2009, 6:45:46 AM9/25/09
to structuremap-users
I've been an avid StructureMap user for awhile, and I love it.

Whenever I tell people about StructureMap (or using DI in general), I
mention that two of the benefits are that (a) StructureMap will create
objects and all their dependencies for you and (b) it enables you to
fake out the dependencies in a test.

Why do we need constructor injection to do this? I can call
ObjectFactory.GetInstance() anytime I want and it will work. And I
could leave SM configured for my tests and call ObjectFactory.Inject()
to stub things out.

So theoretically, I wouldn't even need constructor injection, right?
The only case where I would really see where I would need it is if I'm
writing a test and I need a specific ISomeService as a dependency for
one class in the test and a different ISomeService for another class
in the test. But I'd think that that would not be the norm, and I
could always fall back to constructor in that case.

Am I missing something?

Jon

Mark Nijhof

unread,
Sep 25, 2009, 7:37:16 AM9/25/09
to structure...@googlegroups.com
Because then every class that you use ObjectFactory will get the
dependency on StructureMap. This whole thing is to get rid of hard
dependencies so taking one on the specific framework that helps you
achieve this would probably be a weird thing to do. Normally you would
have a few places where you call ObjectFactory directly and everything
else is injected. So application start, web service start, controller
factory are places that come to mind.

Also testing with the IoC is a pain, you want to be explicite about
the things you are testing, you want to be able to reset state after
each test (even if you are testing behavior). The IoC is just not a
good thing to have in your tests, you would probably get weird errors
in your tests because of this (un-expected of course)

Hope this helps.

-Mark

Jon Kruger

unread,
Sep 25, 2009, 7:46:18 AM9/25/09
to structure...@googlegroups.com
Why is it bad if my classes have a dependency on StructureMap?  I suppose there might be a case where that matters (if I'm writing code that some other project that doesn't use SM might reuse), but in my case, I'm just writing code for my one project, so I don't think that's an issue in my case. 

I think ObjectFactory.Inject() is pretty explicit, and I can call ObjectFactory.ResetDefaults() after each test (I have this in my test base class so that it automatically happens every time).  I have a few parts of my app where SM is wired up in unit tests (because it made sense in those cases) and it's made things a lot easier for those cases.  I think that one issue that I might have doing what I propose is that now everything is wired up by default, whereas with constructor injection using an auto-mocker, all of the constructor dependencies are stubs by default, but I don't know how big of a pain that would be since I haven't tried it yet.

I guess what made me think of this in the first place is that if you try and follow the Single Responsibility Principle, you end up with a lot of small classes.  This is good, but I have a situation where I always want a certain set of these small classes to work together in unit tests (in my case, it's classes that do translation using AutoMapper in an MVC app where I translate from domain models to view models and vice versa).  So in this case, I'm not actually testing each individual unit like you normally do, I'm testing a few of those units working together. 

Mark Nijhof

unread,
Sep 25, 2009, 8:20:03 AM9/25/09
to structure...@googlegroups.com
With respect to the comment that you only use it in a small project
and such and so, I think you could than go and say that for any
dependency? What would happen if along the line you realize that
StructureMap is not the appropriate solution to your problem, but you
want to use some other IoC? In that case you are going to have to
change each and every place where you are using this ObjectFactory
stuff in your code, and worse you even have to start changing your
tests. So if everything changes how do you verify that everything is
still 100% working like it was?

I have personally not yet needed an IoC in any unit tests except for
when I am asserting the configuration of this IoC.

-Mark

Jon Kruger

unread,
Sep 25, 2009, 8:28:27 AM9/25/09
to structure...@googlegroups.com
I think I might call YAGNI on that though, I've used StructureMap on several different projects and I can't see any reason why I would switch in the middle of the project.  I suppose at some point I might come to like another DI container better, but it won't be because SM is hampering my project. 

I usually don't use IoC in my unit tests either, and I usually don't recommend people doing it that way (that would be a more advanced usage of SM and I don't know if it'll totally work, which is why I'm asking).  But if it works, it might make writing my tests easier.

Jimmy Bogard

unread,
Sep 25, 2009, 8:35:22 AM9/25/09
to structure...@googlegroups.com
It's about expressing and conveying intent.  If a class requires a dependency to perform its responsibilities, it's a required, primal dependency, and is therefore required to instantiate the component.  Optional dependencies on the other hand, should use property injection, because you can use the class without setting up the dependency.

Except for top-level coordinators (like controllers) which may have many dependencies, the required dependency list of a ctor also describe to the user of the class what the responsibilities of this class are.  See Scott's post for a more thorough description:

http://codebetter.com/blogs/scott.bellware/archive/2007/06/28/164867.aspx

Jon Kruger

unread,
Sep 25, 2009, 8:38:47 AM9/25/09
to structure...@googlegroups.com
Interesting... I only scanned it real quick but that post made some good points.

Mark Nijhof

unread,
Sep 25, 2009, 9:28:36 AM9/25/09
to structure...@googlegroups.com
I would not call it YAGNI, I would like to know why you would not want
to use DI?

And yes Scotts blog post is a very good one thanks for reminding me of that one

-Mark

Jon Kruger

unread,
Sep 25, 2009, 9:30:34 AM9/25/09
to structure...@googlegroups.com
Not sure what you're asking.  Are you asking what benefit I would see by not using constructor injection?

Mark Nijhof

unread,
Sep 25, 2009, 9:35:22 AM9/25/09
to structure...@googlegroups.com
Yes what is your motivation for not wanting to use Ctor injection but
still choose to use an IoC? It seems to me that you then are only
benefiting slightly from what the IoC has to offer you, and I don't
see the benefits for doing so?

-Mark

Jon Kruger

unread,
Sep 25, 2009, 9:48:41 AM9/25/09
to structure...@googlegroups.com
It's a two-step thought process.

I have SM partially wired up in my unit tests because I want a certain set of classes to always work together.  I then realized that setting up my tests became much easier (also because of my project structure), and I was able to set up stuff in my test setup methods by writing methods like this:

CreateStubForValue<Quote>(4);
StubAllConstantsFor<QuoteType>();

Those methods replace several lines of creating stubs with Rhino Mocks, stubbing methods, and injecting the stub into SM.  My test setups are much easier to read and write now.  But what enables me to write stuff like that is that I know that, for example, when these classes that are wired up with SM need to load an object, they are going to ask SM for the class that I injected.  It doesn't matter if the actual class I'm testing has the class that loads an object as a ctor parameter (it usually doesn't).  But now I'm stubbing out classes farther down the stack.  This isn't an issue when you're just testing one class in isolation (which is the normal case), but if you want more than one class to work together, this is a huge deal (at least it has been to me).

So that got me thinking, if i can just ObjectFactory.Inject() everything, why do I need ctor injection?  Ruby people don't use it, and they don't worry about whether you can figure out what they're classes are doing based on their dependencies (as Scott's article argued).  Ruby people don't need DI because they have a way to plug in stubs in tests.  Well, I also have a way to plug in stubs (OF.Inject()).  So why do I need ctor injection?  Sometimes if feels like needless ceremony, or a leaky abstraction out of the DI container.  The DI container knows how to create objects whether I have ctor parameters or not.

True story time.  Yesterday I had to add a dependency to my MVC controller base class.  I didn't want to have to go and add another ctor parameter to every controller in my system.  So I just got the dependency with OF.GetInstance() and wired up my base test class to account for it.  I wrote less code, it was easier, I got it done faster, and I didn't break other classes.  That just seemed like a big win to me.

So I guess that's what led me to wonder if this would work.

Mark Nijhof

unread,
Sep 25, 2009, 9:59:17 AM9/25/09
to structure...@googlegroups.com
I agree with you on integration tests and using the IoC there. And I
am sure that it will work for you the way that you are already
working, I would however not so quickly change towards that approach.
But then again I am pretty explicit about what I want :)

-Mark

Jon Kruger

unread,
Sep 25, 2009, 10:02:54 AM9/25/09
to structure...@googlegroups.com
Yeah, what I'm proposing could be a total fail... I was partially asking to see if anyone told me they tried it and it failed.  Maybe I just need to try it on a sample project and see what happens.  The Ruby thing I mentioned in my last post really got me thinking that it could work.

Mark Nijhof

unread,
Sep 25, 2009, 10:17:27 AM9/25/09
to structure...@googlegroups.com
I think one thing you should keep in mind that C# is not Ruby :)

-Mark

Steven Harman

unread,
Sep 25, 2009, 6:31:54 PM9/25/09
to structure...@googlegroups.com
I started to write up a reply with a few of my thoughts, and it got pretty lengthy so I just blogged it instead: http://stevenharman.net/blog/archive/2009/09/25/prefer-dependency-injection-to-service-location.aspx

-steve

Dru Sellers

unread,
Sep 25, 2009, 6:47:43 PM9/25/09
to structure...@googlegroups.com
+1 steve

Evan Hoff

unread,
Sep 25, 2009, 7:02:15 PM9/25/09
to structure...@googlegroups.com
+1 on the post

Evan

Reply all
Reply to author
Forward
0 new messages