AutoMockContainer with support for automocking classes with non-interface dependencies

后端 未结 1 947
死守一世寂寞
死守一世寂寞 2020-12-28 10:31

I have a constructor which has a non-interface dependency:

public MainWindowViewModel(IWorkItemProvider workItemProvider, WeekNavigatorViewModel weekNavigato         


        
1条回答
  •  醉梦人生
    2020-12-28 10:58

    You can pretty easily write one yourself if you leverage a DI Container that supports just-in-time resolution of requested types.

    I recently wrote a prototype for exactly that purpose using Autofac and Moq, but other containers could be used instead.

    Here's the appropriate IRegistrationSource:

    public class AutoMockingRegistrationSource : IRegistrationSource
    {
        private readonly MockFactory mockFactory;
    
        public AutoMockingRegistrationSource()
        {
            this.mockFactory = new MockFactory(MockBehavior.Default);
            this.mockFactory.CallBase = true;
            this.mockFactory.DefaultValue = DefaultValue.Mock;
        }
    
        public MockFactory MockFactory
        {
            get { return this.mockFactory; }
        }
    
        #region IRegistrationSource Members
    
        public IEnumerable RegistrationsFor(
            Service service,
            Func> registrationAccessor)
        {
            var swt = service as IServiceWithType;
            if (swt == null)
            {
                yield break;
            }
    
            var existingReg = registrationAccessor(service);
            if (existingReg.Any())
            {
                yield break;
            }
    
            var reg = RegistrationBuilder.ForDelegate((c, p) =>
                {
                    var createMethod = 
                        typeof(MockFactory).GetMethod("Create", Type.EmptyTypes).MakeGenericMethod(swt.ServiceType);
                    return ((Mock)createMethod.Invoke(this.MockFactory, null)).Object;
                }).As(swt.ServiceType).CreateRegistration();
    
            yield return reg;
        }
    
        #endregion
    }
    

    You can now set up the container in a unit test like this:

    [TestMethod]
    public void ContainerCanCreate()
    {
        // Fixture setup
        var builder = new ContainerBuilder();
        builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
        builder.RegisterSource(new AutoMockingRegistrationSource());
        var container = builder.Build();
        // Exercise system
        var result = container.Resolve();
        // Verify outcome
        Assert.IsNotNull(result);
        // Teardown
    }
    

    That's all you need to get started.

    MyClass is a concrete class with an abstract dependency. Here is the constructor signature:

    public MyClass(ISomeInterface some)
    

    Notice that you don't have to use Autofac (or any other DI Container) in your production code.

    0 讨论(0)
提交回复
热议问题