-We use constructor dependency injection (and sometimes
properties) because it’s important to expose your dependencies…
-… so that callers who aren’t using IoC (ahem
tests) can easily work with the test in isolation by using mocks and not
having to involve an IoC container…
-… and so it behooves us to keep the number of
dependencies in a class down to a minimum to keep tests from getting too
complicated…
-… which also forces us to battle between
too-many-dependencies and dependencies-that-do-too-much.
Basically, it seems like we make a lot of choices based on
writing tests and the fact that our tests don’t use IoC (to keep things
less complicated, we tell ourselves).
Now, I happen to buy into this, and it has worked
well. But… what if… we started allowing an IoC container to
creep into our test playground, also (of course with something handy like AMC
to populate the container with the more mundane stuff).
This opens up a whole new style of dependency management,
IMHO. What if we designed classes to _require_ some form of IoC
container. What if passing every dependency into the c’tor or
properties isn’t the best way (every time)?
Bellware (and others) have talked about the various forms of
dependencies (opaque, etc) and the one where a given class goes out and gets
all its dependencies from the container itself (as opposed to having them
injected) is ‘close’ and ‘not horrible’, but not
perfect.
What if we require you to pass in a single ‘dependency
resolver’ interface (which is basically the IoC container) into the c’tor
from which the dependencies are gathered?
“What does this gain us?” you may ask.
Well, it prevents your tests from having to know about all the dependencies in
a given class. It makes tests less brittle as you can add and remove
dependencies without having to change as many tests – or changing the
tests dramatically. It requires less setup and less expectation management just
to get to some interesting part to test. The AMC, container, and the
class-under-test could work out themselves what needs to be mocked in order to
satisfy the dependencies of the class and your test can interact only with the
mocks you need to interact with in order to pass
the test.
I haven’t had a chance to put any of this to code
(yet), but this occurred to me at the TDD CodingDojo today (more about that
later) and I thought it might work. I’ll try to whip up some
examples of what I’m talking about and I may find that it’s not
worth doing, but I’m willing to bet that this may address some of the
friction of what to mock, how many, what expectations, etc.
I've done this in the past by creating 2 constructors: - one explicitly takes the dependencies - one no-arg constructor, which calls into the IoC container to...
I basically do the same thing as Jimmy. It came back to bite me once: I was using a class in a unit test with the no-arg constuctor, and the IoC container...
... I'm a little tired right now... but I read your post a few times and I'm not quite sure what the problem you're trying to solve is. Is it the number of...
... I see this as purely aesthetic, I don't think there's any tangible need to "fix" this. ... This is a problem sometimes, but like you said, it's often a...
... I've thought this was a problem as well, but I tend to agree with Aaron that it's largely aesthetic. However, I have sort of toyed with the idea of whether...
Playing the devil's advocate, is this the symptom of: - An anemic domain model or - A coordinator with too many concerns This might happen when a domain...
This issue seems to frequently boil down to the decision about whether or not I'm injecting something explicitly through the constructor, or relying on a...
Hi all - forgive my interjection. This is my first post to this list, though I've been lurking for a while. It would appear that you're systemically increasing...
Can you explain the benefit of passing the container to the service over using the AMC ? It looks to me like a lot more work. ... Can you explain the benefit...
Ayende Rahien
Ayende@...
Feb 10, 2008 8:01 am
It's unclear to me how passing in the container is substantially different from using it statically....
Either way it is more work than just DI ... Either way it is more work than just DI On 2/10/08, Shawn Hinsey < smhinsey@... > wrote: ... <*> Your email...
Ayende Rahien
Ayende@...
Feb 10, 2008 8:19 am
I'd tend to agree. Maybe some code samples would help....
I'm not sure I follow your question. 'passing the container to the service' and 'using AMC' are not mutually exclusive. AMC would straddle the container...
Why on earth would I want the class to be aware of the container? Let us make take this example: public SmsSender(ILogger logger, IAlertGenerator generator,...
Ayende Rahien
Ayende@...
Feb 10, 2008 6:02 pm
(Ayende Rahien said...) ... Aware-of and directly-referencing are two different things. ... (NOTE: I wouldn't pass IKernel in there and thus strongly bind...
Service Locator taints the application with knowledge of the container, it makes dependencies less obvious, and in general means that I have to read code...
Ayende Rahien
Ayende@...
Feb 11, 2008 8:11 pm
It "taints" it with knowledge of the service locator, you may or may not be using IoC for your service locator. Personally I remember reading Fowlers article...
How much time do you spend in the ctor? For myself, I almost always let R# deal with the ctor and never touch (or look) at it....
Ayende Rahien
Ayende@...
Feb 11, 2008 8:18 pm
I'm not saying that it takes me an age to create the constructor though. I am just saying that if you find a class has a lot of dependencies in its interface...
It sounds like you're advocating partial adherence to the dependency inversion principle. If you're putting service locators inside a class, you're creating...
... Fowler covers this better than I could so there is no point me regurgitating (http://www.martinfowler.com/articles/injection.html#ServiceLocatorVsD ...
I think I'm misunderstanding your usage of a service locator. This is what's in my head, an opaque dependency w/ a service locator: public AccountService() { ...
... is ... INotificationSender. But ... I.e., ... Nope thats pretty much it. In this case you are coupled to the Service Locator which is a simple class you...
Maybe I missed it, but haven't anyone throw out the property setter approach for optional dependencies. This still allows a container to be used and removes...