2012-01-25 14 views
8

Vorrei "combinare" le asserzioni di raccolta e le asserzioni di proprietà di Fluent Assertion, ad es. asserire che due IEnumerable sono equivalenti a coppie usando il confronto proprietà-per-proprietà (possibilmente "annidato") (cioè l'uguaglianza strutturale, nel linguaggio del linguaggio funzionale).Come combinare le asserzioni di raccolta e proprietà usando le affermazioni fluenti?

Esempio concreto:

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

Qui ho scritto un metodo di estensione ToSelectListItems che converte un Dictionary a un IEnumerable di SelectListItem s (da ASP.NET MVC). Voglio affermare che actual e expected sono "strutturalmente" uguale, rilevando che il tipo di riferimento SelectListItem non sovrascrive Equal s e utilizza quindi l'uguaglianza riferimento predefinita.

Aggiornamento

Attualmente utilizzando la seguente soluzione di laminati a mano, ancora sperando in qualcosa di meglio integrato nel 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)); 
} 

(nota: Zip qui è la mia IEnumerable estensione che usa Tuple.Create come la proiezione predefinita)

Aggiornamento 2

Ecco due esempi minimali:

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

risposta

6

ho aggiunto il supporto per lo scenario nel ramo principale di asserzioni fluente. Farà parte della prossima versione, ma ci potrebbe volere un mese o due per accumulare abbastanza modifiche per garantire un altro rilascio. Se vuoi, puoi prendere la build di origine ed eseguire il release.bat per creare una versione intermedia.

+1

Ho risolto la soluzione di Stephens per lavorare anche con i tipi di valore, se T era un valore-tipo non funzionava senza questa correzione: https://gist.github.com/1877672 –

+0

È nella beta pubblica della versione 2.0 http : //fluentassertions.codeplex.com/releases/view/82423 –

+3

E come è supportato? Non riesco a trovare un esempio di documentazione. – ferpega

7

Se io sto interpretando la sua domanda, penso che si dovrebbe provare la versione 1.7.0 di asserzioni fluente. In quella versione abbiamo cambiato il comportamento che quando viene utilizzato IncludingNestedObjects, lo farà anche sulle raccolte di oggetti. Un estratto della documentazione.

"Inoltre, è possibile effettuare il confronto strutturale di un ulteriore livello includendo la proprietà IncludingNestedObjects.Questo istruirà il confronto per confrontare tutti (insiemi di) tipi complessi a cui si riferiscono le proprietà dell'oggetto (in questo esempio). di default, asserirà che le proprietà nidificate dell'oggetto corrispondono alle proprietà nidificate dell'oggetto previsto.Tuttavia, se si specifica SharedProperties, verranno confrontate solo le proprietà ugualmente denominate tra gli oggetti nidificati.Ad esempio:

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

+0

Ciao Dennis, grazie per l'attenzione. Sto usando 1.7.0, ma il problema è che (usando il tuo esempio) 'dto' e' customer' sono entrambe sottoclassi di 'IEnumerable <'T>' e quindi non hanno alcuna proprietà condivisa (gli elementi che contengono fanno, ma non gli IEnumerable stessi). Così sto ricevendo 'System.InvalidOperationException: Si prega di specificare alcune proprietà da includere nel confronto. in FluentAssertions.Assertions.PropertyEqualityValidator.Validate (tracker UniqueObjectTracker, String parentPropertyName) ' –

+0

Quindi, si intende che sia' actual' che 'expected' rappresentano collezioni enumerabili con oggetti che non sono esattamente uguali, ma hanno le stesse proprietà? –

+0

corretto. _ _ _ _ _ _ _ _ –