2

以下内容在 XUnit 中未断言为真(StartDate 和 EndDate 是 DatePeriod 仅有的两个公共属性):

var actual = new List<DatePeriod>()
{
    new DatePeriod() { StartDate = new DateTime(2017, 1, 20), EndDate = new DateTime(2018, 1, 19)},
    new DatePeriod() { StartDate = new DateTime(2018, 1, 20), EndDate = new DateTime(2018, 3, 31)}
};

var expected = new List<DatePeriod>()
{
    new DatePeriod() { StartDate = new DateTime(2017, 1, 20), EndDate = new DateTime(2018, 1, 19)},
    new DatePeriod() { StartDate = new DateTime(2018, 1, 20), EndDate = new DateTime(2018, 3, 31)}
};

Assert.Equal(actual, expected);

根据一些研究,我预计在最新版本的 XUnit 中,这些最终会被认为是平等的,因为在使用 Assert 时,只要顺序相同。

4

2 回答 2

4

您只需要覆盖EqualsGetHashCode像这样:

public class DatePeriod
{
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;

        DatePeriod other = (DatePeriod)obj;

        return StartDate.Equals(other.StartDate) && EndDate.Equals(other.EndDate);
    }

    public override int GetHashCode()
    {
        return new {StartDate, EndDate}.GetHashCode();
    }

    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}

xUnit 在您可以调用的意义上识别集合,Assert.Equal而其他测试框架需要特殊方法,例如CollectionAssert.AreEqual.

在所有情况下,框架都会Equals为列表中的每个项目调用,并从另一个列表传递相应的项目。如果您有一个字符串或整数列表,那么Equals默认情况下会正确实现。对于像这样的自定义对象DatePeriod,该Equals方法的默认实现基于引用相等,即两个对象相等是指它们实际上是同一个对象。要获得基于值的相等性,您必须重写该Equals方法(以及GetHashCode推荐的方法)。

于 2016-03-28T18:00:02.237 回答
3

List<T>不检查元素到元素的相等性。

使用 LINQ 的SequenceEqual方法来检查你的相等性。

var equal = actual.SequenceEqual(expected);

IEquatable在您的对象上实施:

public class DatePeriod : IEquatable<DatePeriod>
{
     public DateTime StartDate { get; set; }
     public DateTime EndDate { get; set; }

     public bool Equals(Period other)
     {
         return StartDate == other.StartDate && EndDate == other.EndDate;
     }
}

为了安全起见,检查空值和什么不是。有关更完整的实现,请参阅 Yacoub 的答案。

于 2016-03-28T17:54:35.920 回答