Reputation: 26183
How do you Setup a generic returntype in Moq?
I have the following interface:
public interface IFoo
{
T Bar<T>();
}
Now I want to setup Bar<T>()
to work inside a test
var foo = new Mock<IFoo>();
foo.Setup(x => x.Bar<It.IsAnyType>()).Returns(new Mock<???>().Object);
How do I fill out ???
, or if that is not possible, then how do I return a generic mock?
There are 100s of types, I am trying to avoid mocking them all. The test breaks (because the code throws and exception) if the call returns null for any type, which is sadly the default non-mocked behavior.
Upvotes: 4
Views: 2350
Reputation: 1
As was stated before, a reference type is required to create a mock:
public interface IFoo
{
T Bar<T>() where T : class;
}
Now, it is possible to create a Mock<T>
using reflection.
This is really ugly, but it works also when interfaces are passed as 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);
}));
Upvotes: 0
Reputation: 1121
Try using this Returns
overload: IReturnsResult<TMock> Returns(InvocationFunc valueFunction);
Setup:
factory.Setup(m => m.Create<It.IsAnyType>())
.Returns(new InvocationFunc(invocation =>
{
var typeArgument = invocation.Method.GetGenericArguments()[0];
return Activator.CreateInstance(typeArgument);
});
Call:
var something = factory.Object.Create<Something>();
Upvotes: 1
Reputation: 247443
If T
is a reference type ie
public interface IFoo {
T Bar<T>() where T : class;
}
Then it would be easier to just create a slim mock
public class MockFoo : IFoo {
private MockFoo() {
}
public T Bar<T>() where T : class => Mock.Of<T>();
public static IFoo New() => new MockFoo();
}
which can be initialized while arranging the test and using MOQ for mocking the output of Bar
//Arrange
IFoo foo = MockFoo.New();
//...
Upvotes: 1