How to Mock (with Moq) Unity methods

后端 未结 4 1156
别跟我提以往
别跟我提以往 2021-01-04 04:04

Extension methods are not good for testing (that\'s described here: Mocking Extension Methods with Moq, http://www.clariusconsulting.net/blogs/kzu/archive/2009/12/22/Howtomo

4条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-04 04:39

    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() where TFrom : class;
        void RegisterType() where TTo : TFrom;
        void RegisterType(string name) where TTo : TFrom;
        void RegisterType(Type from, Type to);
        void RegisterType(Type from, Type to, string name);
    
        void RegisterInstance(TFrom instance) where TFrom : class;
    
        T Resolve();
        T Resolve(string name);
        IEnumerable ResolveAll();
    
        bool IsRegistered(string name) where TFrom : class;
        bool IsRegistered() where TFrom : class;
    }
    
    
    public class DIContainer : IDIContainer {
        IUnityContainer m_Container = new UnityContainer();
    
        #region IDIContainer Members
    
        public void RegisterType() where TFrom : class {
            m_Container.RegisterType();
        }
    
        public void RegisterType() where TTo : TFrom {
            m_Container.RegisterType();
        }
    
        public void RegisterType(string name) where TTo : TFrom {
            m_Container.RegisterType(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 instance) where TFrom : class {
            m_Container.RegisterInstance(instance);
        }
    
        public T Resolve() {
            return m_Container.Resolve();
        }
    
        public IEnumerable ResolveAll() {
            return m_Container.ResolveAll();
        }
    
        public T Resolve(string name) {
            return m_Container.Resolve(name);
        }
    
        public bool IsRegistered(string name) where TFrom : class {
            return m_Container.IsRegistered(name);
        }
    
        public bool IsRegistered() where TFrom : class {
            return m_Container.IsRegistered();
        }
    
        #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();
    
            ... 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 mockLog = new Mock();
        Mock containerMock = new Mock();
    
        //Setup mock container to return a log mock we set up earlier
        containerMock.Setup(c=>c.Resolve()),Returns(mockLog);
        //Verify that all setups have been performed
        containerMock.VerifyAll();
      }
    }
    

提交回复
热议问题