如何使用Moq模拟接口的`object.Equals(object obj)`

kol*_*man 10 .net c# moq

我有一个有趣的问题包围你的头.考虑一下这样的界面:

public interface IMyThing
{
    int Id { get; }
}
Run Code Online (Sandbox Code Playgroud)

现在我想测试使用此接口的代码.也许有一些LINQ魔术.像这样的东西:

public class SomeClass
{
    private IMyThing _thing;

    ...

    public bool HasThing(IEnumerable<IMyThing> things)
    {
        return things.Contains(_thing);
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在嘲笑所有IMyThing使用的对象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;
}
Run Code Online (Sandbox Code Playgroud)

这就是事情.上面的代码编译没有警告,但永远不会工作.MoqEquals()方法创建一个拦截器,但永远不会到达.而是调用对象代理的equals方法.我谴责的事实是我在嘲笑一个界面而不是一个具体的类.

更新:刚刚意识到Moq甚至没有创建一个拦截器.

当然我可以IMyThing像这样扩充界面:

public interface IMyThing : IEquatable<IMyThing>
{
    int Id { get; }
}
Run Code Online (Sandbox Code Playgroud)

LINQ运算符将识别该IEquatable<T>接口并使用它.

我不想这样做是因为:

  • 这仅适用于其他IMyThing对象
  • IEquatable<T> 不是为了这个目的
  • 我不想让我的模型变得模糊不清

你怎么解决这个问题?

kol*_*man 6

我最终Moq在Github 上为该项目贡献代码(参见问题#248).有了这个改变有可能嘲笑object.Equals(object obj),object.GetHashCode()并且object.ToString(),即使是接口嘲笑.

让我们看看它是否被接受.