I have an interface
public interface IDataProvider
{
T GetDataDocument(Guid document) where T:class, new()
}
I\'d like to mock
I had a similar issue, I chose against using a stub in this situation as I did not want additions to the interface being tested to require immediate changes to the test code. i.e. adding a new method should not break my existing tests.
To get the mock working I added all the public type in a given assembly at runtime.
//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 )
{
}
With Moq 4.13 or later you can do this
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);
}));
For the particular test you are going to use this mock for, you probably know what T will be, right?
simply just setup the mock for that:
myMock.Setup(m => m.GetDataDocument<MyDataClass>()>(It.IsAny<Guid>()))
.Returns(() => new MyDataClass());
It's not really recommended to reuse the mocks anyway, so go ahead and setup mocks for the actual test at hand.
Instead of using a mock, maybe your case would be better to use a Stub.
public class StubDataProvider : IDataProvider
{
public T GetDataDocument<T>(Guid document) where T : class, new()
{
return new T();
}
}
If you truly need a mock (so you can verify that GetDataDocument
was called). Instead of trying to wrestle with a Mocking framework it sometimes is easier to just create a Mock class out right.
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();
}
}
And than in your test:
bool wasCalled = false;
IDataProvider dataProvider = new MockDataProvider(() => { wasCalled = true; });
var aTable = dataProvider.GetDataDocument<ATable>(new Guid());
Debug.Assert(wasCalled);