c# - 如何使用依赖注入(inject)模拟通用工厂

标签 c# unit-testing moq

使用 Ninject,我有一个这样注册的工厂:

kernel.Bind<IMyFactory>().ToFactory();

IMyFactory 看起来像这样:

public interface IMyFactory
{
    T CreateInstance<T> where T : MyBaseClass;
}

原因是从 MyBaseClass 派生的类有它们自己的依赖关系,我需要能够从它们的类型创建这些类的实例,我这样做是这样的:

MethodInfo mi = factory.GetType().GetMethod("CreateFoo");
MethodInfo generic = mi.MakeGenericMethod(type);
var param = (MyBaseClass)generic.Invoke(factory, null);

其中factory是Ninject创建的IMyFactory实例,typeMyBaseClass派生类的类型我想创造。这一切都非常有效。

问题是我希望能够使用 Visual Studio 和 Moq 中的测试框架对此进行单元测试,但我找不到模拟 IMyFactory 的好方法。

目前我有这个:

myFactory = new Mock<IMyFactory>();
myFactory.Setup(d => d.CreateFoo<MyFirstClass>()).Returns(new MyFirstClass(userService.Object));
myFactory.Setup(d => d.CreateFoo<MySecondClass>()).Returns(new MySecondClass(userService.Object, someOtherServiceMock.Object));
// repeat for as many classes as would usually be handled by IMyFactory

显然这真的很乏味(我有几十门课要做)。有更好的方法吗?

最佳答案

这有点麻烦,而且我不确定它是否是正确的测试策略,但这是一种似乎有效的方法。我在我的测试类中创建了一个这样的函数:

    private Dictionary<Type, Mock> mocks;

    private void SetupCreateFoo<T>(Mock<IMyFactory> myFactory) where T: MyBaseClass 
    {
        var t = typeof(T);
        var constructors = from constructor in t.GetConstructors()
                           let parameters = constructor.GetParameters()
                           where parameters.Length > 0
                           select new { constructor, parameters };

        // Note: there should only be one constructor anyway           
        foreach (var c in constructors)
        {
            List<object> parameters = new List<object>();
            foreach (var p in c.parameters)
            {
                parameters.Add(mocks[p.ParameterType].Object);
            }
            myFactory.Setup(d => d.CreateAnalytic<T>()).Returns((T)c.constructor.Invoke(parameters.ToArray()));
        }
    }

哪里有字典mocks是从 MyBaseClass 派生的类可能需要的模拟服务的集合.

现在我可以设置我的测试类,我可以这样做:

    [TestInitialize]
    public void Setup()
    {
        userService = new Mock<IUserService>();
        //... setup userService
        someOtherServiceMock = new Mock<ISomeOtherService>();
        //... setup someOtherService

        mocks = new Dictionary<Type, Mock>()
        {
            { typeof(IUserService), userService },
            { typeof(ISomeOtherService), someOtherServiceMock}
        };

        myFactory= new Mock<IMyFactory>();
        SetupCreateFoo<MyFirstClass>(myFactory);
        SetupCreateFoo<MySecondClass>(myFactory);
        // ... etc
        finderService = new FinderService(userService.Object, myFactory.Object);

    }

而且我认为我可以设置一个 List<Type>并调用SetupCreateFoo<T>在循环中以进一步减少重复,但需要再次进行一些反射(reflection)才能使用 Type 调用泛型方法。 .

关于c# - 如何使用依赖注入(inject)模拟通用工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27785701/

相关文章:

c# - 集合的 Where 子句

c# - 带绑定(bind)的扩展 WPF 工具包数据网格

reactjs - NextJS Router & Jest : How can I mock router change event

unit-testing - Grails 测试问题

c# - Moq 中的匹配设置问题

c# - Cisco ASA 5505 系统重新加载(重新引导/重新启动)

c# - ASP.Net MVC 4 Bundles - 在路径名中使用变量

java - 如何为无效返回方法定义 AnswersWithDelay

unit-testing - 使用 Moq 进行单元测试的模拟 Prism 事件聚合器

unit-testing - 为什么 AutoFixture 的 AutoMoqData 不创建模拟对象?