9

我想“组合”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在这里,我编写了一个将 a 转换DictionaryIEnumerableof s的扩展方法SelectListItem(来自 ASP.NET MVC)。我想断言actual并且expected“结构上”相等,注意引用类型SelectListItem不会覆盖Equals 并因此默认使用引用相等。

更新

目前使用以下手动解决方案,仍然希望在 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()
    }
}
4

2 回答 2

7

如果我正确解释了您的问题,我认为您应该尝试Fluent Assertions 的1.7.0版。在那个版本中,我们更改了使用 IncludeNestedObjects 时的行为,它也会对对象集合执行此操作。文档的摘录。

“此外,您可以通过包含 IncludeNestedObjects 属性将结构比较进一步提升。这将指示比较比较主题(在此示例中)的属性所引用的所有(集合)复杂类型。默认情况下,它将断言主体的嵌套属性与预期对象的嵌套属性匹配。但是,如果您确实指定了 SharedProperties,那么它只会比较嵌套对象之间的同名属性。例如:

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

于 2012-01-26T07:36:46.383 回答
7

我在 Fluent Assertions 的主分支中添加了对您的场景的支持。它将成为下一个版本的一部分,但我们可能需要一两个月才能积累足够的更改以保证另一个版本的发布。如果需要,您可以获取源构建并运行 release.bat 来构建中间版本。

于 2012-02-16T19:47:58.530 回答