使用 XUnit Assert 函数比较两个 List<T>
Comparing two List<T> with the XUnit Assert function
以下不是 XUnit 断言为真(StartDate 和 EndDate 是 DatePeriod 仅有的两个 public 属性):
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 时就会被认为是相等的。
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 的回答以获得更完整的实现。
您只需像这样覆盖 Equals
和 GetHashCode
:
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
方法)。
以下不是 XUnit 断言为真(StartDate 和 EndDate 是 DatePeriod 仅有的两个 public 属性):
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 时就会被认为是相等的。
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 的回答以获得更完整的实现。
您只需像这样覆盖 Equals
和 GetHashCode
:
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
方法)。