0

I have an application that is using Unity for DI but I have run into a bit of a snag while writing my unit tests. In a handful of my business layer methods I have code that is similar to this:

var obj = container.Resolve<ISomeObj>();

This is either standing up an in-memory object that will ultimately be passed off to the database, or it is an in-memory object that will ultimately be passed up to the client. The issue though is that RhinoMocks is (seemingly) unable to mock the container properly so doing something like this:

 mockContainer = MockRepository.GenerateMock<IUnityContainer>();
 mockContainer.Expect(x => x.Resolve<ISomeObj>())
            .Return(mockObj);

Getting an exception here seems to make sense since the container is actually empty, but I am not seeing a straightforward way around the problem. I had considered abstracting the container away with a wrapper to get around this problem but that seems to be a bit overkill.

Any thoughts or suggestions are greatly appreciated!

----EDIT----

Since Yacoub posted his answer I have been doing some reading about the Service Locator (anti) Pattern and while it seems to be generally accepted that it is an anti pattern, I haven't found an answer on what to do with POCOs.

Using my example above it seems like the general answer to my problem is to do something like this:

public class Foo()
{
    private ISomeObj someObj;
    public Foo(ISomeObj injectObj)
    {
        someObj = injectObj;
    }
}

I suppose that my only complaint with this approach is that it will (potentially) make the constructor "busy" ala:

public class Foo()
{
    public Foo(ISomeService injectSvc, ISomeObj injectObj, ISomeObj2 injectObj2, ISomeObj3 injectObj3)
    {
        ...
    }
}

Further, unless I am missing something, I would need a way to reinitialize a given instance for reuse. Meaning: if MethodA() and MethodB() both consume ISomeObj, when MethodA() finishes with ISomeObj I would need someway to reinitialize all of the fields in ISomeObj so that MethodB() could do its work.

What is the "best" way to approach this problem?

dparsons
  • 2,812
  • 5
  • 28
  • 44

1 Answers1

5

What you are doing (resolving objects using the container from inside your business layer methods) is called Service Location and is considered an anti-pattern. You might want to consider refactoring to use Constructor Injection. And if you do that then you wouldn't need to use the container in your unit tests.

Having said that, here is what you can do without such refactoring: Don't mock the container. Instead, use a real container, and register the mock instance with the container like this:

container.RegisterInstance<ISomeObj>(mockObj); //mockObj is the mocking object that implements ISomeObj

All resolve operations done for this interface (ISomeObj) will return the same instance.

If you need to be able to obtain a new instance for each resolve operation, you can do the following:

container.RegisterType<ISomeObj>(new InjectionFactory(x => GenerateMock()));

Where GenerateMock is the method that creates the mock object. You can replace this call with the code that create the mock using RhinoMocks.

Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62