【问题标题】:Comparing two List<T> with the XUnit Assert function将两个 List<T> 与 XUnit Assert 函数进行比较
【发布时间】:2016-03-28 17:45:12
【问题描述】:

以下内容在 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 时只要顺序相同。

【问题讨论】:

  • EqualsGetHashCode 方法是在 Period 中定义的吗?
  • 不,我需要这样做吗?
  • @YacoubMassad 请查看我对您的回答的评论,我不得不稍微更新我的帖子,因为没有 Period 对象,一切都只使用 DatePeriod。

标签: c# assert xunit xunit.net xunit2


【解决方案1】:

您只需像这样覆盖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 方法)。

【讨论】:

  • 嘿,这似乎正是我所需要的,但你能看看我最近对我的帖子所做的更新吗?我很抱歉,因为没有 Period 这样的对象。一切都使用 DatePeriod。
  • @BlakeRivell 你最初有一个 List,里面有一系列 Period,这导致 Yacoub 相信 Period 是 DatePeriod 的子类。
  • @TheAnathema 正确,这就是为什么我试图让他知道我在 cmets 中的错误并询问他是否可以更新他的答案。
  • 不,有时我会使用它,因为我有一个自定义的比较逻辑,它不是对象本身固有的。例如,在某些情况下,我只想比较 ID 而不是其余属性。例如,当您创建Dictionary 时,您可以传递此类自定义比较器。
  • 如果有一个“标准”的方式来比较对象,那么你应该把这样的比较逻辑放在对象本身上。如果比较逻辑是自定义的,则将其放入自定义对象(实现IEqualityComparer)。
【解决方案2】:

List&lt;T&gt; 不检查元素到元素的相等性。

使用 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 的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    相关资源
    最近更新 更多