使用 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
实例,type
是MyBaseClass
派生类的类型我想创造。这一切都非常有效。
问题是我希望能够使用 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/