12

我们编写了一个如下所示的测试。此测试需要,我们已经连接Equal - 过载创造了CodeTableItem -class:将[AutoFixture] SemanticComparison Of OfikeAlike应用于序列/集合/数组/ IEnumerable

ICollection<CodeTableItem> expectedValutaList = new List<CodeTableItem>(); 
expectedValutaList.Add(new CodeTableItem("DKK", "DKK")); 
expectedValutaList.Add(new CodeTableItem("EUR", "EUR")); 
RepoDac target = new RepoDac(); 

var actual = target.GetValutaKd(); 

CollectionAssert.AreEqual(expectedValutaList.ToList(),actual.ToList()); 

测试工作正常,但不幸的依赖于Equality功能全,意思是,如果我有一个扩展CodeTableItem -class更多的领域,并忘记扩展Equals功能,单元测试仍然运行绿色,虽然我们不测试所有领域。我们希望避免这种Equality污染(请参阅Test Specific Equality),该文字仅为符合该测试而编写。

我们使用OfLikeness尝试,并以这种方式重写了测试:

ICollection<CodeTableItem> expectedValutaList = new List<CodeTableItem>(); 
expectedValutaList.Add(new CodeTableItem("DKK", "DKK")); 
expectedValutaList.Add(new CodeTableItem("EUR", "EUR")); 
var expectedValutaListWithLikeness = 
      expectedValutaList.AsSource().OfLikeness<List<CodeTableItem>>(); 

RepoDac target = new RepoDac(); 
ICollection<CodeTableItem> actual; 

actual = target.GetValutaKd(); 

expectedValutaListWithLikeness.ShouldEqual(actual.ToList()); 

但测试失败,因为Capacity是不相等的。我已经编写了多次运行反射的代码,并且通常最终会执行忽略字段的重载。有没有办法忽略OfLikenessShouldEqual的某些字段?或者有解决这个问题的其他方法吗?

回答

8

只需添加.Without(x => x.Capacity),Likeness实例在比较值时将忽略Capacity属性。

var expectedValutaListWithLikeness = 
     expectedValutaList.AsSource().OfLikeness<List<CodeTableItem>>() 
     .Without(x => x.Capacity); 

更新:

正如马克·塞曼在他的回答中指出,你可能想要的是对对方的每个元素进行比较。这里有一个稍微不同的方式,可以让你执行灵活的比较非常的

假设RepoDac类返回类似:

public class RepoDac 
{ 
    public ICollection<CodeTableItem> GetValutaKd() 
    { 
     return new[] 
     { 
      new CodeTableItem("DKK", "DKK"), 
      new CodeTableItem("EUR", "EUR") 
     }; 
    } 
} 

有关expectedValutaList每个实例,您可以创建一个覆盖动态代理Equals已采用神似:

var object1 = new CodeTableItem("DKK", "DKK1") 
    .AsSource().OfLikeness<CodeTableItem>() 
    .Without(x => x.Property2) 
    .CreateProxy(); 

var object2 = new CodeTableItem("EUR2", "EUR") 
    .AsSource().OfLikeness<CodeTableItem>() 
    .Without(x => x.Property1) 
    .CreateProxy(); 

注意如何object1和object2甚至具有不同的动态生成的Equals。 (第一忽略Property2而第二忽略Property1。)

下测试通过:

var expected = new List<CodeTableItem>(); 
expected.Add(object1); 
expected.Add(object2); 

var target = new RepoDac(); 
var actual = target.GetValutaKd(); 

Assert.IsTrue(expected.SequenceEqual(actual)); 

注:

,要求开始与expected实例,它包含动态生成的代理(重写Equals)。

您可能会找到有关此功能的更多信息here

12

为什么你不想那样做

我不认为创建任何List<T>神似做你想让它做什么。据我所知,你想比较两个列表中的内容。这与比较两个列表不一样...

请考虑一下相似性:它比较属性值。 List<T>有哪些属性?

他们

  • 容量
  • 计数

由于尼科斯Baxevanis在他的回答中指出,可以使用不讲究方法忽略容量属性的值,但是这意味着只有Count属性保留。

换句话说,如果你这样做,这一点:

expectedValutaListWithLikeness.ShouldEqual(actual.ToList()); 

在功能上等价于:

Assert.AreEqual(expected.Count, actual.Count) 

换句话说,名单可能有完全不同的数据,但如果只有每个列表具有相同数量的元素,测试仍然会通过。这可能不是你想要的...

你应该做的

您可以使用象形互相反对的每个元素进行比较。像这样的东西应该工作:

var expectedValutaList = new List<CodeTableItem>(); 
expectedValutaList.Add(new CodeTableItem("DKK", "DKK")); 
expectedValutaList.Add(new CodeTableItem("EUR", "EUR")); 

var expectedValutaListWithLikeness = from cti in expectedValutaList 
            select cti 
             .AsSource() 
             .OfLikeness<CodeTableItem>(); 

var target = new RepoDac(); 

var actual = target.GetValutaKd(); 

Assert.IsTrue(expectedValutaListWithLikeness.Cast<object>().SequenceEqual(
    actual.Cast<object>())); 

您可能还可以使用CollectionAssert的说法,但它已经这么多年了,因为我最后一次使用MSTest的,我不记得方法的怪癖...

+0

非常感谢Mark,做到了!优雅! – 2012-08-02 07:56:37

3

以下的答案必须从me asking myself a duplicate of this question发出,请参见下面

你可以使用一个SequenceLike操作这暗示LINQ的SequenceEqual运营商。

这可以写出: -

[Theory, AutoData] 
public void ShouldMap( Dto inputDto) 
{ 
    var mapped = inputDto.ToModel(); 

    inputDto.AsSource().OfLikeness<Model>() 
     .Without(x => x.IgnorableProperty) 
     .With(x => x.Tags).EqualsWhen((dto, model) => 
      model.Tags.SequenceLike(dto.Tags)) 
     .ShouldEqual(mapped); 
} 

闪亮短执行所有功能于一身的帮手基于@马克西曼的回答感谢,以从@Nikos Baxevanis提示的: -

static class LikenessSequenceExtensions 
{ 
    public static bool SequenceLike<T, TSource>(this IEnumerable<T> that, IEnumerable<TSource> source) 
    { 
     return SequenceLike<T, TSource>(that, source, x => x); 
    } 

    public static bool SequenceLike<T, TSource>(this IEnumerable<T> that, IEnumerable<TSource> source, Func<Likeness<TSource, T>, IEquatable<T>> customizeLikeness) 
    { 
     return source.Select(x => customizeLikeness(x.AsSource().OfLikeness<T>())).SequenceEqual(that.Cast<object>()); 
    } 
} 

我原来的执行:

static class LikenessSequenceExtensions0 
{ 
    public static bool SequenceLike0<T, TSource>(this T[] that, TSource[] source) 
    { 
     return source.SequenceLike0(that, likeness => likeness); 
    } 

    public static bool SequenceLike0<T, TSource>(this T[] that, TSource[] source, Func<Likeness<TSource, T>, IEquatable<T>> customizeLikeness) 
    { 
     return source.SequenceEqual(that, (x, y) => customizeLikeness(x.AsSource().OfLikeness<T>()).Equals(y)); 
    } 

    public static bool SequenceEqual<T, TSource>(this T[] that, TSource[] source, Func<T, TSource, bool> equals) 
    { 
     return that.Length == source.Length && that.Zip(source, Tuple.Create).All(x => equals(x.Item1, x.Item2)); 
    } 
} 

副本原件问题

我在寻找我的基于xunit.AutoFixture的测试管理Test Specific Equality数组/ IEnumerable<T>/seq<'T>最彻底的方法。

OOTB(我已经失去了我学习这个的地方的参考),Ploeh.SemanticComparisonLikeness版本高达2.12只适用于单个项目。

将相同的技术应用于项目集合(理想情况下是OOTB,但对扩展方法的判断套件非常开放)以便于表达包含嵌入对象的组合项目的相似度的最佳方式是什么?

这真的是一个自我回答,所以我可以隐藏帮手,并允许一个地方放置一个“你这样做在V nn”应该像未来提供序列支持,但它不会我第一次对AFflicted AFiionados提供的答案的微妙之处感到惊讶

+0

伟大的代码...谢谢! – AxelEckenberger 2013-01-25 18:10:34

3

我想让其他人有这个问题 - 使用Ruben的第二个代码示例,您想要比较Calendar和Calendar。假期,同时定制两者的比较:

var expectedCalendar = newCalendar.AsSource() 
    .OfLikeness<Calendar>() 
    .Without(c=>c.Id) //guid, will never be equal 
    .With(c=>c.Holidays).EqualsWhen((source, dest) => 
     source.Holidays.SequenceLike(dest.Holidays, holiday => 
      holiday.Without(h=>h.SecondsUntil) //changes every second 
    )); 

在这个例子中,你首先设置属性排除,等日历对象。然后,您为处理Holidays集合提供一个自定义的EqualsWith实现。假日=> lambda然后允许您自定义子级比较,就像父级一样。只要你喜欢大量的括号,你就可以继续嵌套。

+0

+1不错。嘿,那些友好的拥抱括号非常安慰:) – 2013-01-25 18:15:44

相关问题