2012-01-25 12 views
8

Chciałbym "połączyć" asercje kolekcji i asercje własności, np. twierdzą, że dwa numery IEnumerable są parami równymi, używając porównania właściwości według właściwości (prawdopodobnie "zagnieżdżonych") (to znaczy równości strukturalnej, w języku funkcjonalnym).Jak połączyć asercje kolekcji i własności za pomocą twierdzeń płynnych?

konkretny przykład:

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"} 
}; 

Tutaj napisałem metodę rozszerzenia ToSelectListItems który konwertuje Dictionary do IEnumerable z SelectListItem s (z ASP.NET MVC). Chcę twierdzić, że actual i expected są "strukturalnie" równe, zwracając uwagę, że typ odniesienia SelectListItem nie zastępuje Equal s i dlatego domyślnie używa równości odniesienia.

Aktualizacja

Obecnie stosując następujące ręcznie walcowane rozwiązanie, wciąż mając nadzieję na coś lepszego wbudowanym 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)); 
} 

(uwaga: Zip Oto mój własny IEnumerable rozbudowa który wykorzystuje Tuple.Create jako domyślna projekcja)

Aktualizacja 2

Oto dwa przykłady: minimalne

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() 
    } 
} 

Odpowiedz

6

Dodałem wsparcie dla twojego scenariusza w głównej gałęzi Fluent Assuranceions. Będzie to część następnej wersji, ale może zająć nam miesiąc lub dwa, aby nabrać wystarczających zmian, by uzasadnić kolejne wydanie. Jeśli chcesz, możesz pobrać kompilację źródłową i uruchomić plik release.bat, aby utworzyć wersję pośrednią.

+1

Naprawiłem obejście Stephensa, aby pracować z wartościowymi typami, jeśli T było typem wartości, nie działało bez tej poprawki: https://gist.github.com/1877672 –

+0

Jest w publicznej wersji beta wersji 2.0 http: : //fluentassertions.codeplex.com/releases/view/82423 –

+3

Jak to jest obsługiwane? Nie mogę znaleźć przykładu dokumentacji. – ferpega

7

Jeśli mam poprawnie interpretując swoje pytanie, myślę, że powinieneś spróbować wersję 1.7.0 Fluent twierdzeń. W tej wersji zmieniliśmy zachowanie, które jest używane podczas IncludingNestedObjects, a także w kolekcjach obiektów. Fragment dokumentacji.

"Możesz dodatkowo porównać konstrukcję, wprowadzając właściwość IncludingNestedObjects, która pokaże porównanie w celu porównania wszystkich (zbiorów) typów złożonych, do których odnoszą się właściwości obiektu (w tym przykładzie). domyślnie będzie twierdzić, że zagnieżdżone właściwości tematu pasują do zagnieżdżonych właściwości oczekiwanego obiektu, ale jeśli wybierzesz SharedProperties, to będzie porównywać tylko te same właściwości między zagnieżdżonymi obiektami, na przykład:

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

+0

Cześć Dennis, dziękuję za uwagę. Używam 1.7.0, ale problem polega na tym, że (używając twojego przykładu) 'dto' i' customer' to obie podklasy 'IEnumerable <'T>' i dlatego nie mają żadnych wspólnych właściwości (elementy, które zawierają, ale nie samych siebie samych). W ten sposób otrzymuję "System.InvalidOperationException: proszę podać niektóre właściwości do uwzględnienia w porównaniu. at FluentAssertions.Assertions.PropertyEqualityValidator.Validate (UniqueObjectTracker tracker, String parentPropertyName) ' –

+0

Czy masz na myśli, że zarówno' actual' jak i 'expected' reprezentują kolekcje przeliczalne z obiektami, które nie są dokładnie takie same, ale mają te same właściwości? –

+0

Prawidłowo. _ _ _ _ _ _ _ _ –

Powiązane problemy