views:

504

answers:

5

Hi

I'm trying to learn dependency injection and have come across a problem, when unit testing the application.

I'm writing a console application and the container is created and initialized in Main(), it's available as a get-property in Program.Container, so anywhere in my application I can call Program.Container.Resolve<..>().

I have a ServiceValidator class like this:

public class ServiceValidator
{
    private readonly IConfiguration _configuration;
    private readonly IService _service;

    public ServiceValidator(IConfiguration configuration, IService service)
    {
        _configuration = configuration;
        _service = service;
    }

In another class I use

ServiceValidator serviceValidator = Program.Container.Resolve<ServiceValidator>();
serviceValidator.VerifyVersion();

It's the call to Program.Container.Resolve that causes me problems in the unit test, as it hasn't been setup.

Is that a bad practice, to call resolve on the container? I could create the ServiceValidator instance in Main() and pass the object around, but that seems stupid as it would cause lots of parameters for the objects that are just passed around to the next method.

So I guess it's acceptable to call Resolve within a class, but then the container must be configured for the unit test. How should I do that, should I move the container to another place than the Program class? What would you recommend?

If it matters, I'm using Unity and C#

Thanks :-)

+1  A: 

I usually allow calls to resolve dependencies from the container in places like main although I still try to keep them to a minimum. What I then do is configure the container in an initialization method of a test class. I have it initialized with fake implementations for any test class which needs to call the container.

Test classes which don't call anything requiring the container be initialized are then able to ignore it and not use the fakes. I usually use mocks in those instances.

I also use the Microsoft Service Locator so that the dependency that I am taking is on something from the .NET Framework instead of on a specific container. This allows me to down the road use anything I want even a home brewed container.

Brendan Enrick
I would still like to see a nice pattern on how to solve this without making a dependency on the Program class...
Peter Lillevold
>I keep calls like that..Do you mean 'resolve' calls to the container?
Karsten
Yes, I do mean 'resolve' calls to the container.
Brendan Enrick
A: 

You could use a static class as an initializer for your container. Something like BootStrapper.cs would fine. You can then reference the class methods both in your code and tests.

Mohamed Osman
A: 

Well what you're technically doing is a service location in your class.

I remember reading this article a while back:

http://martinfowler.com/articles/injection.html

For my classes I never try to use Resolve in them. I create the objects through the container when I need them. For Unit testing, I either use some mock library and stub classes.

Min
+4  A: 

Is that a bad practice, to call resolve on the container? I could create the ServiceValidator instance in Main() and pass the object around, but that seems stupid as it would cause lots of parameters for the objects that are just passed around to the next method.

When you use dependency injection all the way, then you won't need to pass lots of parameters to objects. The constructor of each object should have as parameters only those dependencies which it itself uses directly - it won't know about the transitive dependencies of its direct dependencies.

So if you have a class X which requires a ServiceValidator, then class X will have a constructor parameter of type ServiceValidator. Then if some class Y uses class X, then class Y will have a constructor parameter of type X. Notice that Y knows nothing about ServiceValidator, so you don't need to pass the ServiceValidator from one class to another - the only place where it is used is when constructing X, and that is often done by a DI framework or in only one place in a hand-written factory.

Some links for more information:

Esko Luontola
>When you use dependency injection all the way, >then you won't need to pass lots of parameters to objects.I never considered doing DI for all classes. I just wanted to do DI for the classes that uses external stuff, like web services, databases, perhaps configuration. If I understand you correct, you would never call resolve or new on anything but framework classes?Thanks for your answer :-)
Karsten
Came to think of another thing. Does it mean that all objects are created up front, a long time before they may actually be needed, perhaps they are not even needed at all?
Karsten
When using DI all the way, you bootstrap the application by getting your application's root object from the DI container, and after that you don't anymore access the container directly. http://docs.google.com/Doc?id=dd2fhx4z_5df5hw8#xefn The objects will be created when some object which has them as a dependency is created. In general, all objects with the same lifecycle scope are instantiated at the same time. If some objects have a different lifecycle scope, then you can inject a factory for instantiating them at the right time.
Esko Luontola
A: 

The problem lies in the fact that you are trying to test the Main method. This method is virtually impossible to unit test.

I would argue that it is best not to unit test your Main method because:

  • The emphasis of modern unit testing is about design
  • You should minimize the dependency on configuration in unit tests. Configuration can be tested with smoke or integration tests.
Dries Van Hansewijck
No, I don't try to test the Main method.
Karsten