最小起订量等于仅适用于IEquatable

本文关键字:于仅 适用于 IEquatable | 更新日期: 2023-09-27 18:35:53

我正在使用Moq框架进行单元测试,我遇到了这个有趣的问题。

public interface Bar : IEquatable<Bar>
{
}
[TestClass]
public class TestClass
{
    Mock<Bar> a;
    Mock<Bar> b;
    public TestClass()
    {
        a = new Mock<Bar>();
        b = new Mock<Bar>();
        a.Setup(bar => bar.Equals(b.Object)).Returns(true);
    }
    [TestMethod]
    public void AssertEqualsTest()
    {
        Assert.AreEqual(a.Object, b.Object); //fails
    }
    [TestMethod]
    public void AssertIsTrueTest()
    {
         Assert.IsTrue(a.Object.Equals(b.Object)); //passes
    }
}

第一期

所以Assert.AreEqual只是失败了。我不想每次需要检查相等性时都必须使用第二个测试中的行,即使我的大多数(如果不是全部)类都继承自 IEquatable。

您可能会认为它失败了,因为安装程序只设置 IEquality.Equals() 函数(Assert.AreEqual可能不会检查),但如果添加该行

a.Setup(x => x.Equals((object)b.Object)).Returns(true);

对于构造函数,它仍然失败。

第二期

如果从接口声明中注释掉: IEquatable<Bar>(以便a.Setup覆盖object.Equals),则两个测试都将失败。

我想要的结果是能够在Mock对象上设置等于并调用Assert.AreEqual

最小起订量等于仅适用于IEquatable

第一期

通过点皮克检查。 Assert.AreEqual调用静态方法object.Equals来比较实例。 object.Equals首先使用operator ==,由于模拟实例不实现该运算符,因此这将默认为比较引用。显然,a 和 b 是不同的实例,因此比较返回 false。

第二期

我没有看过 Moq 的内部结构,但我认为发生这种情况是因为接口没有声明 Equals 方法。已通过以下方法确认(成功):

public interface IBar
{
}
public class Bar : IBar
{
    public override bool Equals(object obj)
    {
        return false;
    }
}
[TestClass]
public class Class1
{
    [TestMethod]
    public void TestMoq()
    {
        var a = new Mock<Bar>();
        var b = new Mock<Bar>();
        a.Setup(bar => bar.Equals(b.Object)).Returns(true);
        Assert.IsTrue(a.Object.Equals(b.Object));
    }
}

如果我删除Bar.Equals覆盖,测试也将失败。只是一个猜测,但由于Moq在内部使用Castle,这个问题可以通过这个问答来解释。

无论如何,我认为您现在正在对Assert.IsTrue(a.Object.Equals(b.Object));IEquatable所做的是足够的解决方法。

顺便说一句,正如 JaredPar 上面问的那样,你为什么要比较模拟?

我用过..

mockLine2.CallBase = True

为什么呢?

我们正在测试订单服务。由于订单有两行,服务将删除与某些条件匹配的任何行。行是一个 IList,List (etc) 使用 .equals() 来查找你想要的项目,所以要删除该行,你需要一个通过的 equals 实现:

Assert.IsTrue(mockLine2.Object.Equals(mockLine2.Object)

"Moq mock 没有检测到一条线等于自己,因此订单上的行集合将无法找到该行。"

你可能会争辩说,由于 Order 不是被测试的类,我们应该嘲笑 Order 并断言order.Lines.Remove()是用正确的行调用的,但我们发现总的来说,使用真正的域对象(它们都相当愚蠢)比模拟它们更痛苦。