2

I'm using an IoC container instead of DI via constructor injection. Some may ask why I'm using IoC containers instead of constructor injection. Well for reasons stated here: Why do I need an IoC container as opposed to straightforward DI code?. However, I'm finding it difficult to create unit tests for my services. I'm not sure how to mock the repositories used by my services during runtime since I'm not using constructor injection (a conundrum). Anyone have any solutions?

For example:

public class SomeService
{
    private ISomeServiceRepository someServiceRepository;

    public GetSomeThing()
    {
        //how do I mock this repository in my unit test
        someServiceRepository = IoC.Resolve<ISomeServiceRepository>();

        someData = someServiceRepository.getData();

        someOtherService = new SomeOtherService();
        someThing = someOtherService.GetSomeThing();

        return FigureOutSomeThingElse(someData, someThing);
    }

    public FigureOutSomeThingElse(someData, someThing)
    {
        //do some figuring
        return somethingElse;
    }
} 

public class SomeOtherService
{
    private ISomeServiceRepository someOtherServiceRepository;

    public GetSomeThing()
    {
        //how do I mock this repository in my unit test
        someOtherServiceRepository = IoC.Resolve<ISomeOtherServiceRepository>();

        var someData = someOtherServiceRepository.getData();
        return someData;
    }
}
Community
  • 1
  • 1
Joe Web
  • 128
  • 1
  • 1
  • 7
  • "Anyone have any solutions?". Yes: Use constructor injection! – Steven Jul 12 '12 at 18:05
  • constructor injection can get messy real fast, unless you're building mom and pop applications. For instance, I start of with this New SomeService (ISomeRepository), but then later on requirements change and I have to add this New SomeService(ISomeRepository, IAnotherRepository). Now I have to go back and change a bunch of code. – Joe Web Jul 17 '12 at 15:01
  • If ctor injection gets messy, you're doing it wrong. Search around here on SO, you'll find many about ctor injection, and many good answers explaining what why ctor injection is the way to go, and what you're doing wrong when it's not working out for you. – Steven Jul 17 '12 at 15:03
  • Hey I'm opened minded, but how do you get around the issue I explained above? – Joe Web Jul 17 '12 at 15:21
  • "Well for reasons stated here". Can you restate what your exact problems are. It's hard for me to find out what your problems are from the supplied link. – Steven Jul 18 '12 at 16:26

3 Answers3

2

People can easily launch into a diatribe about how "you're doing it wrong" with resolve as needed, but I have experienced the pain of old code bases that cannot grok the register-resolve-release pattern altruistically. I would, however, advise against using a static container reference (as in IoC.) and try to make the container itself at least injected.

In this situation, you simply provide a test version of the IoC registration container, but instead of the normal app configuration you code a test configuration.

This won't be mocking or stubbing in any true sense and in fact these terms can confuse the solution quite a bit.

In essence it'll just be a different active configuration when in the unit tests. You'll still have to register types manually and you might have difficulty disabling the current configuration code if it is in the execution path of the unit tests.

We have a container that we resolve from as needed in an IoC pattern (for a handful of types), and for testing we simply created a new container (basically, one configuration for code and another for unit tests). Our use case was slightly different in that we injected the container into classes instead of having a static accessible type as in your case.

Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
2

You really should not be using IOC.Resolve inside of your class methods. It is very close to newing up your code anyway, which is part of what you are trying to avoid using DI. A better, and more testable way to write this would be something like this.

Public Class SomeService
{

  ISomeServiceRepository someServiceRepository;

  public SomeService(ISomeServiceRepository someServiceRepository)
  {
    this.someServiceRepository = someServiceRepository
  }

  Public GetSomeThing()
  {

    someData = someServiceRepository.getData();
    ...
  }
}

By doing it this way, you can just mock your interface and inject it directly.

If you must use .Resolve, then Adam's approach is the best you can do

Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
  • 1
    It isn't anywhere near `new`ing up, what is provided is decided externally, hence the I in IoC. One downside with resolve from a static container is the service locator pattern reliance. Our solution met in the middle, we inject the container so have a sort of DIoC lol – Adam Houldsworth Jul 11 '12 at 13:59
  • Justin, thanks for the input but you need to take a look at this -> http://stackoverflow.com/questions/871405/why-do-i-need-an-ioc-container-as-opposed-to-straightforward-di-code. Which explains why you don't want to use constructor injection. – Joe Web Jul 11 '12 at 14:03
  • @JustinPihony That said, I agree with your sentiment that injection would be easily testable and likely preferable in this instance. – Adam Houldsworth Jul 11 '12 at 14:06
  • @JoeWeb and Adam I would counter with http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx And, glancing (I will read more thoroughly shortly), I would disagree with the usage of the IoC. You should have a top level .Resolve, sure, but I am saying it should not be inside of your children methods. I will read that post more thoroughly and leave a fuller response there – Justin Pihony Jul 11 '12 at 14:07
  • @JustinPihony I am a fence sitter of the anti-pattern argument, because I have never been presented with a viable alternative. That said, if the IoC container were to be injected, you could alleviate some of the negative effects of the service locator behaviour. Lots of existing applications (as in, apps that don't use IoC from day one) simply **cannot** grok the register-resolve-release pattern, I have experienced that first-hand unfortunately - hence we struck a balance. It is proving to be both testable and maintainable, which reduces how much I care for the zealot arguments against it. – Adam Houldsworth Jul 11 '12 at 14:09
  • @AdamHouldsworth As I mentioned, I merely am presenting an alternative, but defer to your solution if not possible. I preach pragmatism over dogmatism. There are many things that I could respond, but that is not really the point of comments...and many of the back and forths have already seemingly been said on the referenced SO question. I will continue to feel that if IoC is used properly and has recursive resolving and is being injected from the topmost level and trickling down, then it is not problematic. That is the point I was trying to make in a nutshell – Justin Pihony Jul 11 '12 at 14:13
  • @JustinPihony I agree with that point, but was just referring to the instances where the application is past the point where you can configure injection from the root object. I always find this topic quite interesting personally, I have no opinion either way (or more accurately, my opinion is that so long as it proves testable and maintainable, nothing else matters). I was kind of hoping you'd present an alternative to the service locator pattern (that isn't IoC :-) – Adam Houldsworth Jul 11 '12 at 14:15
  • @AdamHouldsworth Sorry, I would love to boast that I am that smart, but I have yet to figure something better...and havent been pushed to think on the subject as I have been lucky enough to have my projects work from the root with an IoC – Justin Pihony Jul 11 '12 at 14:37
0

I got it, this is what I did...

(I'm using Unity.Net & RhinoMock)

  • Created a baseUnitTest class that implements the IContainerAccessor

  • Created and initialized a new instance of the UnityContainer in the constructor

  • Created a "UnityContainer" readonly public property which implements IContainerAccessor.Container

  • Created a unit test class that inherits baseUnitTest

  • Added the following code in a test method...

    Mocker = New Rhino.Mocks.MockRepository()

    SomeRepository = Mocker.DynamicMock(Of ISomeRepository)()

    MyBase.UnityContainer.RegisterInstance(Of ISomeRepository)(SomeRepository)

    Rhino.Mocks.Expect.Call(Of SomeResult)(SomeRepository.SomeMethod("someArg")).Return(New SomeResult())

    Mocker.ReplayAll()

    someService = New SomeService()

    'this method uses IOC.Resolve(ISomeRepository) and calls the SomeRepository.SomeMethod someResult = someService.someMethod()

    Assert.IsNotNull(someResult)

  • Done

Joe Web
  • 128
  • 1
  • 1
  • 7