施加[AutoFixture] SemanticComparison OfLikeness到序列/集

2019-06-26 15:34发布

我们写了一个测试,如下所示。 此测试需要,我们已经建立的连接Equal的-过载CodeTableItem -class:

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的污染(见测试具体的平等 ),已经只写了符合测试。

我们已经尝试使用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 ? 还是有解决这个问题的一些其他的方式?

Answer 1:

为什么你不想那样做

我不认为任何创造一个神似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的,我不记得方法的怪癖...



Answer 2:

只需添加.Without(x => x.Capacity)和相象实例将忽略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您可以创建一个覆盖使用神似等于动态代理:

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和对象2怎么会有甚至不同的动态生成等于。 (第一忽略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)实例。

您可能会发现该功能的详细信息在这里 。



Answer 3:

我想更加明确,对遇到此问题的人 - 使用鲁本的第二个代码示例,要比较这两个日历和Calendar.Holidays,而定制两者的对比:

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
   ));

在这个例子中,你首先设置属性排除等日历对象。 然后你给一个自定义EqualsWith实施处理假期集合。 假日=>拉姆达然后允许您自定义的孩子比较,就像父母。 您可以继续筑巢,只要你喜欢很多括号。



Answer 4:

以下的答案必须从发出我问自己这个问题的一个副本 ,见下文

你可以使用一个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 ) );
    }
}

副本原件问题

我在寻找管理干净的方式测试特定的平等的阵列/ IEnumerable<T> / seq<'T>在我基础xunit.AutoFixture测试。

开箱即用(我已经失去了参考在那里我学到这一点), Ploeh.SemanticComparisonLikeness版本到2.12的作品只有个别项目。

什么是相同的技术应用于项目的集合(理想的开箱即用的,而是扩展方法,良好的判断套件非常开放的),以方便表达,其中包括以组合的方式嵌入对象的项目肖像的最佳方式?

这确实是一个自我的答案,所以我可以藏匿的助手,并允许地方放一个“你做这种方式以V NN”神似应该在未来提供序列的支持,但它不会是我第一次”一直在惊讶与答案的精妙之处可能从受灾爱好者



Answer 5:

我不知道,如果这个问题仍然是相关的,但你正在寻找的是https://github.com/jmansar/SemanticComparisonExtensions

您可以使用.WithCollectionInnerLikeness()做比较,集合,它会得到你想要的到底是什么。



文章来源: Applying [AutoFixture] SemanticComparison OfLikeness to sequences / collections / arrays / IEnumerable