嘲笑任何给定types参数的generics方法调用

我有一个接口

public interface IDataProvider { T GetDataDocument<T>(Guid document) where T:class, new() } 

我想嘲笑它,它会返回一个给定types的新实例,而不pipetypes如何:

 myMock.Setup(m => m.GetDataDocument<It.IsAny<Type>()>(It.IsAny<Guid>())) .Returns(() => new T()); 

(这当然不起作用,因为我不能只给moq任何types的参数,我不知道哪个types必须返回。

任何想法在这一个?

而不是使用模拟,也许你的情况会更好地使用存根 。

 public class StubDataProvider : IDataProvider { public T GetDataDocument<T>(Guid document) where T : class, new() { return new T(); } } 

如果你真的需要一个模拟(所以你可以validationGetDataDocument被称为)。 与其试图与Mocking框架搏斗,有时候更容易创build一个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(); } } 

而且在你的testing中:

 bool wasCalled = false; IDataProvider dataProvider = new MockDataProvider(() => { wasCalled = true; }); var aTable = dataProvider.GetDataDocument<ATable>(new Guid()); Debug.Assert(wasCalled); 

对于你将要使用这个模拟的特定testing,你可能知道T会是什么,对吗?

只是简单地设置模拟:

 myMock.Setup(m => m.GetDataDocument<MyDataClass>()>(It.IsAny<Guid>())) .Returns(() => new MyDataClass()); 

真的不build议重复使用模拟,所以继续设置模拟实际testing。

我有一个类似的问题,我select不要在这种情况下使用存根,因为我不希望添加到被testing的接口需要立即改变testing代码。 即添加一个新的方法不应该打破我现有的testing。

为了得到模拟工作,我在运行时添加了给定程序集中的所有公共types。

 //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 ) { }