I have an interesting problem to wrap your head around. Consider some interface like this one:
public interface IMyThing
{
int Id { get; }
}
Now I want to test code that uses this interface. Maybe something with some LINQ magic. Something like this:
public class SomeClass
{
private IMyThing _thing;
...
public bool HasThing(IEnumerable<IMyThing> things)
{
return things.Contains(_thing);
}
}
I'm mocking all objects implementing IMyThing
using Moq
:
public static IMyThing MockMyThing(int newId)
{
var mock = new Mock<IMyThing>();
mock.Setup(s => s.Id).Returns(newId);
mock.Setup(s => s.Equals(It.IsAny<object>())).Returns<object>(obj =>
{
if (typeof(IMyThing).IsAssignableFrom(obj.GetType()))
{
return ((IMyThing)obj).Id == newId;
}
return false;
});
return mock.Object;
}
Here is the thing. The above code compiles without warnings but will never work. Moq
creates an interceptor for the Equals()
method but it is never reached. Instead, the equals method of the object proxy is called. I'm blaming the fact that I'm mocking an interface but not a concrete class.
UPDATE: Just realised Moq
doesn't even create an interceptor.
Of course I could augment the IMyThing
interface like this:
public interface IMyThing : IEquatable<IMyThing>
{
int Id { get; }
}
The LINQ operator would recognize the IEquatable<T>
interface and use it.
I don't want to do this because:
IMyThing
objectsIEquatable<T>
was not meant for this purposeHow would you solve this?
I ended up contributing code to the Moq
project on Github (see issue #248). With this changes it is possible to mock object.Equals(object obj)
, object.GetHashCode()
and object.ToString()
, even for interface mocks.
Lets see if it gets accepted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With