为什么Assert.AreEqual(x,y)失败,但Assert.AreEqual(y,x)不会失败?

时间:2014-09-02 12:56:02

标签: c# struct assert equality

考虑这个结构:

public struct MyNumber
{
    private readonly int _value;

    public MyNumber(int myNumber)
    {
        _value = myNumber;
    }

    public int Value
    {
        get { return _value; }
    }

    public override bool Equals(object obj)
    {
        if (obj is MyNumber)
            return this == (MyNumber) obj;

        if (obj is int)
            return Value == (int)obj;

        return false;
    }

    public override string ToString()
    {
        return Value.ToString();
    }

    public static implicit operator int(MyNumber myNumber)
    {
        return myNumber.Value;
    }

    public static implicit operator MyNumber(int myNumber)
    {
        return new MyNumber(myNumber);
    }
}

当我在单元测试中这样做时:

Assert.AreEqual(new MyNumber(123), 123);

它是绿色的。

但是这个测试失败了:

Assert.AreEqual(123, new MyNumber(123));

为什么会这样?我猜是因为int类确定了相等性,而在第一种情况下,我的类确定它。但我的班级可以隐式兑换为int,所以不应该有帮助吗?

如何让Assert.AreEqual以两种方式工作?我顺便使用MSTest。

更新

实施IEquatable<int>IComparable<int>无济于事。

3 个答案:

答案 0 :(得分:6)

第一个断言将调用MyNumber.Equals,并且如果要比较的参数是Int32并且它等于MyNumber的值,那么您已经实现了它将成功的方式。

第二个断言将调用Int32.Equals并且它将失败,因为要比较的参数是MyNumberInt32不知道或不理解。

您无法使第二单元测试成功,因为您断言Int32应该等于您的值。它不可能是因为它不同。 Int32.Equals中的代码决定第二个值是否相等。您已经实现了一些可以进行单元测试的转换运算符,因此这些断言应该可以工作:

Assert.AreEqual(123, (int) new MyNumber(123));
Assert.AreEqual((MyNumber) 123, new MyNumber(123));

即使强制转换为implicit,它们也不会被Assert.AreEquals自动调用,因为这个方法需要两个Object类型的参数,你必须像我一样明确地调用它们上方。

由于MyNumber.Equals中的特殊处理,您现在的类型与平等无关,例如MyNumber(123) equals Int32(123)为真,但Int32(123) equals MyNumber(123)为假。你应该避免这种情况,所以我建议你删除MyNumber.Equals中的整数的特殊情况处理,而不是依赖于大多数时候都适合你的隐式强制转换。如果他们不这样做,你将不得不做一个明确的演员。

答案 1 :(得分:2)

引用Object.Equals

  

以下语句必须适用于Equals(Object)方法的所有实现。在列表中,x,y和z表示不是 null 的对象引用。

     
      
  • ...

  •   
  • x.Equals(y)返回与y.Equals(x)相同的值。

  •   

您的Equals实施违反了这一要求。 ((object)x).Equals(123) 必须返回与((object)123).Equals(x)相同的值,如果x不是null,则无论其类型如何。

那里有很多代码,正确地说,假设要求两个对象中的哪一个执行比较并不重要。设计您的代码,以使该假设无效。

实际上,这意味着你必须设计你的类,使比较等于任何整数类型,无论你有多少可能更愿意。

答案 2 :(得分:0)

IComparable<int>结构中实施MyNumber,如下所示:

    public int CompareTo(int other)
    {
        return other.CompareTo(Value);
    }

这将确保所有断言按预期工作,例如:

    Assert.AreEqual(new MyNumber(123), 123);
    Assert.AreEqual(123, new MyNumber(123));
    Assert.Greater(124, new MyNumber(123));
    Assert.Less(124, new MyNumber(125));