如何使用流畅断言组合集合和属性断言?

我想“结合”Fluent Assertion的集合断言和属性断言,例如断言两个IEnumerable是成对相等的,使用逐个属性(可能是“嵌套”)比较(即结构相等,用函数式语言说法)。

具体例子:

 var dic = new Dictionary() { {1, "hi"}, {2, "bye" } }; var actual = dic.ToSelectListItems(0).OrderBy(si => si.Text); var expected = new List() { new SelectListItem() {Selected = false, Text="bye", Value="2"}, new SelectListItem() {Selected = false, Text="hi", Value="1"} }; 

在这里,我编写了一个扩展方法ToSelectListItems ,它将Dictionary转换为IEnumerableSelectListItem (来自ASP.NET MVC)。 我想声明actualexpected在“结构上”相等,注意引用类型SelectListItem不会覆盖Equal ,因此默认情况下使用引用相等。

更新

目前使用以下手动解决方案,仍然希望在FluentAssertions中内置更好的内容:

 public static void ShouldBeStructurallyEqualTo(this IEnumerable actual, IEnumerable 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 enumerable1 = new List() { new FooBar() { Foo = "x", Bar = 1 }, new FooBar() { Foo = "y", Bar = 2 } }; List enumerable2 = new List() { 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 enumerable1 = (new List() { new FooBar() { Foo = "x", Bar = 1 }, new FooBar() { Foo = "y", Bar = 2 } }).Cast(); 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() } } 

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

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

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

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