如何设置调用具有特定类型的等于覆盖MoQ中的等于?

Tom*_*mas 3 unit-testing moq equals mocking

使用精细的模拟框架MoQ,我遇到了一个有点令人惊讶的方面(我不喜欢惊喜).我正在嘲笑一个应该在方法调用后添加到集合中的类,如下所示:

public class SomeClass{

}

public class Container {
    private List<SomeClass> classes = new List<SomeClass>();

    public IEnumerable<SomeClass> Classes {
        get {
            return classes;
        }
    }

    public void addSomeClass(SomeClass instance) {
        classes.Add(instance);
    }
}

[Test]
public void ContainerContainsAddedClassAfterAdd() {
    var mockSomeClass = new Mock<SomeClass>();  
    mockSomeClass.Setup(c => c.Equals(mockSomeClass.Object)).Return(true);

    var Container = new Container();
    Container.addSomeClass(mockSomeClass.Object);

    Assert(Container.Classes.Contains(mockSomeClass.Object));
}
Run Code Online (Sandbox Code Playgroud)

这很好用,模拟被添加到Container集合中,并且Equals模拟方法的设置确保IEnumerable.Contains()返回true.然而,总有一些复杂因素.我真正嘲笑的课程并不像我们那么简单SomeClass.它是这样的:

public class SomeClassOverridingEquals{
    public virtual Equals(SomeClassOverridingEquals other) {
        return false;   
    }

    public override Equals(object obj) {
        var other = obj as SomeClassOverridingEquals;

        if (other != null) return Equals(other); // calls the override
        return false;
    }
}

[Test]
public void ContainerContainsAddedClassOverridingEqualsAfterAdd() {
    var mockSomeClass = new Mock<SomeClassOverridingEquals>();  
    mockSomeClass.Setup(c => c.Equals(mockSomeClass.Object)).Return(true);

    var Container = new Container();
    Container.addSomeClass(mockSomeClass.Object);

    Assert(Container.Classes.Contains(mockSomeClass.Object)); // fails
}
Run Code Online (Sandbox Code Playgroud)

该类包含对其自己的特定类型的Equals方法的覆盖,并且Setupmock 的方法似乎无法模拟该特定方法(仅覆盖更一般的方法Equals(object)).因此测试失败.

到目前为止,我还没有办法解决这个相当普遍的模式,除了重写类不使用重写的等号.

我不喜欢那样.

有人有主意吗?

Mar*_*ann 6

我不认为问题出在Moq上,而是使用Contains扩展方法.即使您使用更具体的重载重载了Equals,Enumerable.Contains最终List<T>.Contains也会调用,因为Classes属性实际上是由a支持的List<T>.

List<T>.Contains通过调用实现EqualityComparer<T>.Default.Equals,我认为这默认调用从System.Object继承的Equals方法 - 即:不是你的模拟覆盖的那个,而是将System.Object作为输入的那个.

仔细阅读EqualityComparer<T>.DefaultReflector中的实现,似乎它有类型实现的特殊情况IEquatable<T>,因此如果将该接口添加到类(它已经有适当的方法),它可能表现不同.