2

Does it make sense to mock an IoC container? If so how would I go about it, using Moq?

I am creating a Prism 4 app, using Unity 2.0 as the IoC container. I inject the container into classes that need its services, rather than using Prism's ServiceLocator. For unit testing, unless I need other Prism services for my test, I simply instantiate the container and register mocks with it. I pass the container to the class under test, which resolves the mocks.

It's all fairly simple, but I am wondering if I should mock the container? Why? If so, how would I do that, if I am using Moq as my mocking framework? Thanks for your help.

David Veeneman
  • 18,912
  • 32
  • 122
  • 187

2 Answers2

10

No, it doesn't make sense to mock a DI container because application classes should not reference a container at all.

Instead of injecting the container into the classes, you should inject only the services that they need. This will also mean that you can unit test them without referencing a DI container at all.

Community
  • 1
  • 1
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 4
    do you ever get tired of answering the same question over and over again? – Krzysztof Kozmic Apr 23 '11 at 08:34
  • Thanks, Mark. Those references will help me get a handle on this area. And if you do get tired of answering these questions repeatedly, you are providing valuable assistance to folks like me who are climbing up the learning curve. It is appreciated. – David Veeneman Apr 26 '11 at 00:06
  • 1
    Mark has a book coming out titled "Dependency Injection in .NET", and it looks quite good. Hard copy is due in July, eBook is available now: http://manning.com/seemann/ – David Veeneman Apr 26 '11 at 16:22
  • 2
    I've dug into Mark's book--it's quite good. It's clearing up a lot of the puzzling aspects of DI that I have wrestled with for a while. Very worthwhile, and I have better understanding of Mark's answer here. For anyone else researching the issue--it is very fundamental. Well worthwhile to spend a couple of days working through the issue. The understanding I am getting as I research the problem (using Mark's book, for the most part) will result in major changes in how I design apps--for the better. – David Veeneman Apr 28 '11 at 22:12
0

I agree with Mark Seemann's answer generally for 99% of classes this works fine.

There are some factory type classes (perhaps classes that take a Model and convert it to a ViewModel where those ViewModels have dependencies) for which this doesn't work. In these cases, I generally accept the interface for the container, rather than its concrete type (IUnityContainer, in your case) and mock as usual.

public class MyWidgetFactory : IMyWidgetFactory
{
     public MyWidgetFactory(IUnityContainer container)
     {
          //...
     }
     public Widget[] GetWidgets()
     {
         //...
     }
}

public class MyWidgetFactoryConsumer
{
     private Widget[] _widgets;
     public MyWidgetFactoryConsumer(IMyWidgetFactory factory)
     {
          _widgets = factory.GetWidgets();
     }
}

Both of the above classes are testable, with the factory class needing to have a mocked version of the IUnityContainer and the consumer needing only the factory itself mocked.

Anderson Imes
  • 25,500
  • 4
  • 67
  • 82
  • You don't need to do this. With Unity, use [deferred resolution](http://msdn.microsoft.com/en-us/library/ff660854%28v=PandP.20%29.aspx) (automatic factories). – TrueWill Apr 24 '11 at 14:48
  • 1
    No need to do that. The general solution is to use an Abstract Factory: http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container/1945023#1945023 Some containers has support for this out of the box. Castle Windsor has the Typed Factory Facility. – Mark Seemann Apr 24 '11 at 15:07
  • @TrueWill: that's a really great feature. I'm going to respond to Mark Seemann to ask a question that's been plaguing me. See if you have thoughts. – Anderson Imes Apr 24 '11 at 23:42
  • @Mark Seemann: we run into a situation a lot where we are taking a collection of model objects and converting them to ViewModels. These viewModels have application dependencies, but they also need to be passed the Model object or properties of the model object to be constructed correctly. So, instead of passing simple parameters like the abstract factory example you linked to, we would need to pass parameters for construction in addition to application dependencies (we use Unity's ParameterOverride ability for this). What do you do in these situations? – Anderson Imes Apr 24 '11 at 23:45
  • @Mark Seemann: I should say that obviously the Factory could have the dependencies and then pass references to those dependencies to each constructed object, but one of the nice things about dependency injection is changing a constructor signature for more dependencies doesn't require fixing other code. I concede this is a logical alternative, but I was hoping there might be more. – Anderson Imes Apr 24 '11 at 23:48
  • @TrueWill: I'm hating myself for not knowing about that feature. I'm going to change a large portion of our codebase tomorrow based on that. Thank you so much. – Anderson Imes Apr 24 '11 at 23:50
  • @MarkSeemann an example is a class with a constructor like MyIntF(string instanceData1, int instanceData2, IMyService dependency1, IMyOtherService dependency2). In these cases a factory's implementation could simply pass those dependencies in, but when we add new dependencies, the implementation of the factory has to change. This is typically pretty trivial, but if the factory accepts a IoC container and uses parameter overrides, we get to skip this step (pretty nice). What say you? We've been going back and forth about this for a while. – Anderson Imes Apr 25 '11 at 14:46
  • With Castle Windsor this isn't necessary because the Typed Factory facility takes care of that for you. For other containers, if you decide to inject the container into the factory, make sure that you keep that factory together with the application's Composition Root so that you don't pollute the rest of the code base with a reference to the container. That would make the factory part of the application's infrastructure. – Mark Seemann Apr 25 '11 at 15:06
  • @Mark Seemann: yeah, factories are as far as it ever goes. I'll have to look into Castle Windsor. Thanks for the advice. I was hoping you'd have some sort of magical solution. My answer here is based on this conversation (which I've had many times), so hopefully this clarifies it. – Anderson Imes Apr 25 '11 at 20:53