Как объединить утверждения коллекции и свойства, используя беглые утверждения? - PullRequest
8 голосов
/ 25 января 2012

Я хотел бы "объединить" утверждения коллекции Fluent Assertion и утверждения свойств, например, утверждать, что два IEnumerable являются попарно равными, используя сравнение свойство за свойством (возможно, "вложенное") (т.е. структурное равенство, вязык функционального языка).

Конкретный пример:

var dic = new Dictionary<int, string>() { {1, "hi"}, {2, "bye" } };
var actual = dic.ToSelectListItems(0).OrderBy(si => si.Text);

var expected = new List<SelectListItem>() {
    new SelectListItem() {Selected = false, Text="bye", Value="2"},
    new SelectListItem() {Selected = false, Text="hi", Value="1"}
};

Здесь я написал метод расширения ToSelectListItems, который преобразует Dictionary в IEnumerable из SelectListItem s (изASP.NET MVC).Я хочу утверждать, что actual и expected "структурно" равны, отмечая, что ссылочный тип SelectListItem не переопределяет Equal s и, таким образом, использует равенство ссылок по умолчанию.

Обновление

В настоящее время используется следующее свернутое вручную решение, все еще надеясь на что-то лучшее, встроенное в FluentAssertions:

public static void ShouldBeStructurallyEqualTo<T, U>(this IEnumerable<T> actual, IEnumerable<U> expected) {
    actual.Should().HaveCount(expected.Count());
    actual.Zip(expected).ForEach(pair => pair.Item1.ShouldHave().AllProperties().IncludingNestedObjects().EqualTo(pair.Item2));
}

(примечание: Zip здесь мое IEnumerableрасширение, которое использует Tuple.Create в качестве проекции по умолчанию)

Обновление 2

Вот два минимальных примера:

public class FooBar {
    public string Foo { get; set; }
    public int Bar { get; set; }
}

public class TestClass {
    [Test]
    public void MinimalExample() {
        List<FooBar> enumerable1 = new List<FooBar>() { new FooBar() { Foo = "x", Bar = 1 }, new FooBar() { Foo = "y", Bar = 2 } };
        List<FooBar> enumerable2 = new List<FooBar>() { new FooBar() { Foo = "x", Bar = 1 }, new FooBar() { Foo = "y", Bar = 2 } };

        enumerable1.ShouldHave().SharedProperties().IncludingNestedObjects().EqualTo(enumerable2);

        //Test 'TestClass.MinimalExample' failed: System.Reflection.TargetParameterCountException : Parameter count mismatch.
        //    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
        //    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
        //    at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
        //    at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
        //    at FluentAssertions.Assertions.PropertyEqualityValidator.AssertSelectedPropertiesAreEqual(Object subject, Object expected)
        //    at FluentAssertions.Assertions.PropertyEqualityValidator.Validate(UniqueObjectTracker tracker, String parentPropertyName)
        //    at FluentAssertions.Assertions.PropertyEqualityValidator.Validate()
        //    at FluentAssertions.Assertions.PropertyAssertions`1.EqualTo(Object otherObject, String reason, Object[] reasonArgs)
        //    at FluentAssertions.Assertions.PropertyAssertions`1.EqualTo(Object otherObject)
        //    MiscAssertions.cs(32,0): at TestClass.MinimalExample()
    }

    [Test]
    public void MinimalExample2() {
        IEnumerable<FooBar> enumerable1 = (new List<FooBar>() { new FooBar() { Foo = "x", Bar = 1 }, new FooBar() { Foo = "y", Bar = 2 } }).Cast<FooBar>();
        FooBar[] enumerable2 = new [] { new FooBar() { Foo = "x", Bar = 1 }, new FooBar() { Foo = "y", Bar = 2 } };

        enumerable1.ShouldHave().SharedProperties().IncludingNestedObjects().EqualTo(enumerable2);

        //Test 'TestClass.MinimalExample2' failed: System.InvalidOperationException : Please specify some properties to include in the comparison.
        //    at FluentAssertions.Assertions.PropertyEqualityValidator.Validate(UniqueObjectTracker tracker, String parentPropertyName)
        //    at FluentAssertions.Assertions.PropertyEqualityValidator.Validate()
        //    at FluentAssertions.Assertions.PropertyAssertions`1.EqualTo(Object otherObject, String reason, Object[] reasonArgs)
        //    at FluentAssertions.Assertions.PropertyAssertions`1.EqualTo(Object otherObject)
        //    MiscAssertions.cs(52,0): at TestClass.MinimalExample2()
    }
}

Ответы [ 2 ]

7 голосов
/ 26 января 2012

Если я правильно интерпретирую ваш вопрос, я думаю, вам стоит попробовать версию 1.7.0 Свободных утверждений.В этой версии мы изменили поведение, которое, когда используется InclusiveNestedObjects, это также будет делать с коллекциями объектов.Выдержка из документации.

"Кроме того, вы можете дополнительно повысить уровень структурного сравнения, включив свойство InclusiveNestedObjects. Это даст указание сравнивать все (наборы) сложных типов со свойствами объекта (в этом примере) обратитесь к. По умолчанию будет подтверждено, что вложенные свойства субъекта соответствуют вложенным свойствам ожидаемого объекта. Однако, если вы укажете SharedProperties, он будет сравнивать только свойства с одинаковыми именами между вложенными объектами.Например:

dto.ShouldHave().SharedProperties().IncludingNestedObjects.EqualTo(customer); "

6 голосов
/ 16 февраля 2012

Я добавил поддержку вашего сценария в основную ветку Fluent Assertions. Он будет частью следующей версии, но нам может потребоваться месяц или два, чтобы собрать достаточно изменений, чтобы гарантировать очередной выпуск. Если вы хотите, вы можете взять исходную сборку и запустить release.bat для сборки промежуточной версии.

...