嘲笑任何给定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 ) { }