如何在 Moq 中设置通用返回类型?
我有以下界面:
public interface IFoo
{
T Bar<T>();
}
现在我想设置
Bar<T>()
在测试中工作
var foo = new Mock<IFoo>();
foo.Setup(x => x.Bar<It.IsAnyType>()).Returns(new Mock<???>().Object);
我如何填写
???
,或者如果不可能,那么我如何返回通用模拟?
有数百种类型,我试图避免嘲笑它们。 如果调用对于任何类型返回 null,则测试会中断(因为代码会抛出异常),遗憾的是,这是默认的非模拟行为。
如果
T
是引用类型,即
public interface IFoo {
T Bar<T>() where T : class;
}
然后创建一个苗条的模拟会更容易
public class MockFoo : IFoo {
private MockFoo() {
}
public T Bar<T>() where T : class => Mock.Of<T>();
public static IFoo New() => new MockFoo();
}
可以在安排测试时进行初始化,并使用最小起订量来模拟
Bar
的输出
//Arrange
IFoo foo = MockFoo.New();
//...
尝试使用这个
Returns
重载:IReturnsResult<TMock> Returns(InvocationFunc valueFunction);
设置:
factory.Setup(m => m.Create<It.IsAnyType>())
.Returns(new InvocationFunc(invocation =>
{
var typeArgument = invocation.Method.GetGenericArguments()[0];
return Activator.CreateInstance(typeArgument);
});
致电:
var something = factory.Object.Create<Something>();
如前所述,创建模拟需要引用类型:
public interface IFoo
{
T Bar<T>() where T : class;
}
现在,可以使用反射创建
Mock<T>
。
这确实很难看,但当接口作为 T
传递时,或者当使用的类没有默认构造函数时,它也可以工作。
var fooMock = new Mock<IFoo>();
fooMock
.Setup(foo => foo.Bar<It.IsAnyType>())
.Returns(new InvocationFunc(call =>
{
// create type Mock<T> with the type passed to Bar<T>
var typeArg = call.Method.GetGenericArguments()[0];
var mockType = typeof(Mock<>).MakeGenericType(typeArg);
var mock = Activator.CreateInstance(mockType);
// find "Object" property, call get
var objectProperty = mockType.GetProperty(nameof(Mock.Object), typeArg);
return objectProperty.GetValue(mock);
}));