我有一个界面
public interface IDataProvider
{
T GetDataDocument<T>(Guid document) where T:class, new()
}
Run Code Online (Sandbox Code Playgroud)
我想以某种方式模拟它,它只会返回给定类型的新实例,而不管确切的类型,如:
myMock.Setup(m => m.GetDataDocument<It.IsAny<Type>()>(It.IsAny<Guid>()))
.Returns(() => new T());
Run Code Online (Sandbox Code Playgroud)
(当然不起作用,因为我不能只给moq提供任何类型参数,我不知道必须返回哪种类型.
关于这个的任何想法?
Mar*_*man 30
而不是使用模拟,也许你的情况会更好地使用存根.
public class StubDataProvider : IDataProvider
{
public T GetDataDocument<T>(Guid document) where T : class, new()
{
return new T();
}
}
Run Code Online (Sandbox Code Playgroud)
如果你真的需要一个模拟(所以你可以验证GetDataDocument被调用).而不是试图与Mocking框架搏斗,有时更容易创建一个Mock类正确.
public class MockDataProvider : IDataProvider
{
private readonly Action _action;
public MockDataProvider(Action action)
{
_action = action;
}
public T GetDataDocument<T>(Guid document) where T : class, new()
{
_action();
return new T();
}
}
Run Code Online (Sandbox Code Playgroud)
而且比你的测试:
bool wasCalled = false;
IDataProvider dataProvider = new MockDataProvider(() => { wasCalled = true; });
var aTable = dataProvider.GetDataDocument<ATable>(new Guid());
Debug.Assert(wasCalled);
Run Code Online (Sandbox Code Playgroud)
Mik*_*erg 11
对于你要使用这个模拟的特定测试,你可能知道T会是什么,对吧?
只需为此设置模拟:
myMock.Setup(m => m.GetDataDocument<MyDataClass>()>(It.IsAny<Guid>()))
.Returns(() => new MyDataClass());
Run Code Online (Sandbox Code Playgroud)
无论如何都不建议重复使用模拟器,因此请继续设置模拟器以进行实际测试.
使用 Moq 4.13 或更高版本,您可以使用
It.IsAnyType — 匹配任何类型It.IsSubtype<T> — 匹配 T 和 T 的正确子类型It.IsValueType — 只匹配值类型要从泛型参数的值中获取值或对原始方法进行一些其他操作,您可以使用IInvocation参数InvocationAction或InvocationFunc
setup.Callback(new InvocationAction(invocation => ...))setup.Returns(new InvocationFunc(invocation => ...))下面是一个例子:
var myMock = new Mock<IDataProvider>();
myMock.Setup(m => m.GetDataDocument<It.IsAnyType>(It.IsAny<Guid>())).Returns(new InvocationFunc(invocation =>
{
var type = invocation.Method.GetGenericArguments()[0];
return Activator.CreateInstance(type);
}));
Run Code Online (Sandbox Code Playgroud)
我有一个类似的问题,我选择在这种情况下使用存根,因为我不希望添加到被测试的接口需要立即更改测试代码.即添加新方法不应该破坏我现有的测试.
为了使模拟工作,我在运行时添加了给定程序集中的所有公共类型.
//This is fairly expensive so cache the types
static DummyRepository()
{
foreach( var type in typeof( SomeTypeInAssemblyWithModelObjects ).Assembly.GetTypes() )
{
if( !type.IsClass | type.IsAbstract || !type.IsPublic || type.IsGenericTypeDefinition )
{
continue;
}
g_types.Add( type );
}
}
public DummyRepository()
{
MockRepository = new Mock<ISomeRepository>();
var setupLoadBy = GetType().GetMethod( "SetupLoadBy", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod );
foreach( var type in g_types )
{
var loadMethod = setupLoadBy.MakeGenericMethod( type );
loadMethod.Invoke( this, null );
}
}
private void SetupLoadBy<T>()
{
MockRepository.Setup( u => u.Load<T>( It.IsAny<long>() ) ).Returns<long>( LoadById<T> );
}
public T LoadById<T>( long id )
{
}
Run Code Online (Sandbox Code Playgroud)