Как сравнить два анонимных типа или две коллекции разных типов, используя SemanticComparison

1. Есть ли простой способ сравнить два анонимных типа, используя SemanticComparison из AutoFixture? Моя текущая проблема заключается в том, что я не могу построить Likeness для второго анонимного объекта. Упрощенный пример:

var srcAnon = new { time = expectedTime, data = docsArray };
var resultAnon = new { time=actualTime, data = sutResponseArray };

var expectedAlike = srcAnon.AsSource()
            .OfLikeness<??WhatsHere??>()

2. Я думаю, что этот вопрос довольно связан с первым, так как оба они используют SemanticComparison для создания IEquatable Реализации. В этом вопросе Марк Симанн дал ответ о том, как это сделать, используя утверждения MSTest и LINQ. SequenceEqual метод.

Можно ли использовать библиотеку утверждений XUnit2 в аналогичном сценарии? XUnit поддерживает Assert.Equal() для коллекций одного типа, может ли он использоваться для коллекций разных типов, но если элементы реализуют IEquatable (используя Likeness). Примерно так (это не работает как result а также allLikeness есть разные типы):

Assert.Equal(allLikeness.ToArray(),result.ToArray());

1 ответ

Решение

Независимо от какой-либо системы модульного тестирования, вы всегда можете перейти к SequenceEquals<object> перегрузка, которая также требует сравнения. Это позволит вам сравнивать совершенно разные списки. Этот тест демонстрирует, как вы можете "обмануть".NET, "подумав", что два гетерогенных массива идентичны:

[Fact]
public void TestDisparateSequences()
{
    var ints = new[] { 1, 3, 5, 7 };
    var strings = new[] { "foo", "bar", "baz", "qux" };

    Assert.True(
        ints.Cast<object>().SequenceEqual(
            strings.Cast<object>(),
            new TrueComparer<object>()),
        "Arrays look like they are equal.");
}

private class TrueComparer<T> : IEqualityComparer<T>
{
    public bool Equals(T x, T y)
    {
        return true;
    }

    public int GetHashCode(T obj)
    {
        return 0;
    }
}

Этот тест проходит, потому что TrueComparer всегда возвращает истину.

Очевидно, что это не особенно практично, но оно указывает на соответствующие строительные блоки, которые можно использовать для сравнения разнородных последовательностей.

SemantiComparison обеспечивает SemanticComparer<T> класс, который реализует IEqualityComparer<T>, но он работает только для значений одного типа. Таким образом, чтобы использовать его для сравнения разнородных последовательностей, вам необходимо сопоставить один из списков с последовательностью другого типа.

Часто у вас уже есть такая карта, но если нет, то это хорошая мотивация для ее создания. В противном случае вы можете использовать использование семантического сопоставления, такого как AutoMapper.

Предположим, в качестве примера, что у вас есть Foo класс как это:

public class Foo
{
    public int Number { get; set; }

    public string Text { get; set; }
}

и другой Bar класс, очень похоже:

public class Bar
{
    public int Number { get; set; }

    public string Text { get; set; }
}

Теперь вы можете сравнить Foos и баров, используя карту и SemanticComparison<Bar>:

[Fact]
public void TestEquivalentSequences()
{
    var foos = new[]
    {
        new Foo { Number = 42, Text = "ploeh" },
        new Foo { Number = 1337, Text = "fnaah" }
    };
    var bars = new[]
    {
        new Bar { Number = 42, Text = "ploeh" },
        new Bar { Number = 1337, Text = "fnaah" }
    };

    AutoMapper.Mapper.CreateMap<Foo, Bar>();

    Assert.True(
        foos.Select(AutoMapper.Mapper.Map<Bar>).SequenceEqual(
            bars,
            new SemanticComparer<Bar>()),
        "Mapped arrays should be equivalent.");
}

Тем не менее, это сделает вашу жизнь намного проще, если вы дадите своим объектам структурное равенство. Этот ответ только набросок, что возможно, а не то, что рекомендуется.

Другие вопросы по тегам