views:

102

answers:

3

Extension methods are not good for testing (that's described here: http://stackoverflow.com/questions/2295960/mocking-extension-methods-with-moq, http://www.clariusconsulting.net/blogs/kzu/archive/2009/12/22/Howtomockextensionmethods.aspx).

But probably there are some solutions for mocking of Unity methods? In my case I have the following function:

public class MyManager
{
    public MyManager(IUnityContainer container) : base(container) { }

    public IResult DoJob(IData data)
    {
        IMyLog log = MyContainer.Resolve<IMyLog>();

        ... use log.Id ...

        MyContainer.Resolve<...>();//usage for other purposes...
    }

I want to be sure that 'DoJob' method will always get 'IMyLog' object from container, but not from other sources... how could I test that?

My original idea was to change 'DoJob' method implementation and use:

IMyLog log = UnityContainer.Resolve(typeof(IMyLog)) as IMyLog;

But 'Resolve(Type t, ...)' is also an extension method...

Any thoughts are welcome.

P.S. Please note, that 'my log' object is created far-away from MyManager.DoJob...

A: 

Remove the dependency on IUnityContainer and things become a lot easier and cleaner. Instead let unity inject your dependencies which are abstracted into interfaces. These are easily mocked. Here's an example using a little trick with Unity that injects an auto-factory for IMyLog.

public class MyManager
{
   private readonly Func<IMyLog> logFactory;

   public MyManager(Func<IMyLog> logFactory) 
   {
       this.logFactory = logFactory;
   }

   public IResult DoJob(IData data)
   {
       IMyLog log = logFactory();

       ...
   }
}

Or if you don't need to create the instance each time:

public class MyManager
{
   private readonly IMyLog myLog;

   public MyManager(IMyLog myLog) 
   {
       this.myLog = myLog;
   }

   public IResult DoJob(IData data)
   {
       ...
   }
}
TheCodeKing
In my case I need Unity for other purposes too... (original post was updated recently). I probably could extract not a log but a log-factory and check if it's 'GetLogObject' method was called... Thanks for idea.
Budda
A: 

Guess, I found most appropriate solution for test: It is not necessary to mock unity container and check if 'log' object was taken from it. I will just make a mock for 'Log' object, register its object instance in the container and check in test if this log object is really used.

This will do what is required.

        Mock<IMyLog> mockLog = new Mock<IMyLog>();
        mockLog.Setup(mock=>mock.Id).Returns(TestLogId);

        IUnityContainer container = new UnityContainer();
        container
            .RegisterInstance(mockCommandExecutionLog.Object)
            ...
            ;

        ...

        mockLog.Verify(
            mock => mock.Id,
            Times.Once(),
            "It seems like 'Log' object is not used"
            );

Thanks.

Budda
+1  A: 

I will have to disagree with both answers. TheCodeKing, it is entirely legitimate to use IoC interface directly. One example might be a controller factory in ASP.NET project - where one might do non-trivial resolution using multiple methods on IUnityContainer interface.

Hmm... with auto-factory injecting labdas, one never has to unit test the IoC interface directly. You could just pass a lambda and verify that it gets called with the right parameters.

Budda, you should never bring in an IoC container into your unit test. The dependencies must be injected manually.

Below is the solution I use. I basically created a layer of abstraction over IUnityContainer and implemented a simple class that delegates to IUnityContainer. Because my interface does not contain extension methods, I can easily mock it.

public interface IDIContainer {
    void RegisterType<TFrom>() where TFrom : class;
    void RegisterType<TFrom, TTo>() where TTo : TFrom;
    void RegisterType<TFrom, TTo>(string name) where TTo : TFrom;
    void RegisterType(Type from, Type to);
    void RegisterType(Type from, Type to, string name);

    void RegisterInstance<TFrom>(TFrom instance) where TFrom : class;

    T Resolve<T>();
    T Resolve<T>(string name);
    IEnumerable<T> ResolveAll<T>();

    bool IsRegistered<TFrom>(string name) where TFrom : class;
    bool IsRegistered<TFrom>() where TFrom : class;
}


public class DIContainer : IDIContainer {
    IUnityContainer m_Container = new UnityContainer();

    #region IDIContainer Members

    public void RegisterType<TFrom>() where TFrom : class {
        m_Container.RegisterType<TFrom>();
    }

    public void RegisterType<TFrom, TTo>() where TTo : TFrom {
        m_Container.RegisterType<TFrom, TTo>();
    }

    public void RegisterType<TFrom, TTo>(string name) where TTo : TFrom {
        m_Container.RegisterType<TFrom, TTo>(name);
    }

    public void RegisterType(Type from, Type to) {
        m_Container.RegisterType(from, to);
    }

    public void RegisterType(Type from, Type to, string name) {
        m_Container.RegisterType(from, to, name);
    }

    public void RegisterInstance<TFrom>(TFrom instance) where TFrom : class {
        m_Container.RegisterInstance<TFrom>(instance);
    }

    public T Resolve<T>() {
        return m_Container.Resolve<T>();
    }

    public IEnumerable<T> ResolveAll<T>() {
        return m_Container.ResolveAll<T>();
    }

    public T Resolve<T>(string name) {
        return m_Container.Resolve<T>(name);
    }

    public bool IsRegistered<TFrom>(string name) where TFrom : class {
        return m_Container.IsRegistered<TFrom>(name);
    }

    public bool IsRegistered<TFrom>() where TFrom : class {
        return m_Container.IsRegistered<TFrom>();
    }

    #endregion
}

Now, rewrite your class to use IDIContainer:

public class MyManager
{
    public MyManager(IDIContainer container) : base(container) { }

    public IResult DoJob(IData data)
    {
        IMyLog log = MyContainer.Resolve<IMyLog>();

        ... use log.Id ...

        MyContainer.Resolve<...>();//usage for other purposes...
    }
}

And rewrite the unit test like so:

[TestClass]
public class Test {
  [TestMethod]
  public void TestDoJob() {
    Mock<IMyLog> mockLog = new Mock<IMyLog>();
    Mock<IDIContainer> containerMock = new Mock<IDIContainer>();

    //Setup mock container to return a log mock we set up earlier
    containerMock.Setup(c=>c.Resolve<IMyLog>()),Returns(mockLog);
    //Verify that all setups have been performed
    containerMock.VerifyAll();
  }
}
Igor Zevaka
I wasn't saying it's not legitimate to use the IoC, just that it made it easier to test with direct dependencies. The factory scenario was actually used in my example. It can be achieved using the auto-factory feature of Unity without the need to reference the IoC.
TheCodeKing
Igor, thanks, it's a really good solution. Thanks!
Budda
@TheCodeKing Just re-read your post. I didn't know about the auto-factory support. Coupled with `InjectionFactory` you could do away needing to inject the container. I take it all back :)
Igor Zevaka