Come testare l’unità se il mio object è veramente serializzabile?

Sto usando C # 2.0 con Nunit Test. Ho degli oggetti che devono essere serializzati. Questi oggetti sono piuttosto complessi (ereditarietà a diversi livelli e contengono molti oggetti, eventi e delegati).

Come posso creare un Test unitario per essere sicuro che il mio object sia serializzabile in sicurezza?

Ho questo in alcune unità di test qui al lavoro:

MyComplexObject dto = new MyComplexObject(); MemoryStream mem = new MemoryStream(); BinaryFormatter b = new BinaryFormatter(); try { b.Serialize(mem, dto); } catch (Exception ex) { Assert.Fail(ex.Message); } 

Potrebbe aiutarti … forse l’altro metodo può essere migliore ma questo funziona bene.

Ecco un modo generico:

 public static Stream Serialize(object source) { IFormatter formatter = new BinaryFormatter(); Stream stream = new MemoryStream(); formatter.Serialize(stream, source); return stream; } public static T Deserialize(Stream stream) { IFormatter formatter = new BinaryFormatter(); stream.Position = 0; return (T)formatter.Deserialize(stream); } public static T Clone(object source) { return Deserialize(Serialize(source)); } 

Oltre al test di cui sopra – che assicura che il serializzatore accetterà il tuo object, è necessario eseguire un test di andata e ritorno. Deserializzare i risultati su un nuovo object e assicurarsi che le due istanze siano equivalenti.

serializzare l’object (su memoria o su disco), deserializzare, usare la riflessione per confrontare i due, quindi eseguire di nuovo tutti i test di unità per quell’object (eccetto la serializzazione, naturalmente)

questo presuppone che i tuoi test unitari possano accettare un object come bersaglio invece di crearne uno proprio

Ecco una soluzione che utilizza ricorsivamente IsSerializable per verificare che l’object e tutte le sue proprietà siano serializzabili.

  private static void AssertThatTypeAndPropertiesAreSerializable(Type type) { // base case if (type.IsValueType || type == typeof(string)) return; Assert.IsTrue(type.IsSerializable, type + " must be marked [Serializable]"); foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (propertyInfo.PropertyType.IsGenericType) { foreach (var genericArgument in propertyInfo.PropertyType.GetGenericArguments()) { if (genericArgument == type) continue; // base case for circularly referenced properties AssertThatTypeAndPropertiesAreSerializable(genericArgument); } } else if (propertyInfo.GetType() != type) // base case for circularly referenced properties AssertThatTypeAndPropertiesAreSerializable(propertyInfo.PropertyType); } } 

Sfortunatamente, non puoi davvero testare per questo. Immagina questo caso:

 [Serializable] class Foo { public Bar MyBar { get; set; } } [Serializable] class Bar { int x; } class DerivedBar : Bar { } public void TestSerializeFoo() { Serialize(new Foo()); // OK Serialize(new Foo() { MyBar = new Bar() }; // OK Serialize(new Foo() { MyBar = new DerivedBar() }; // Boom } 

Probabilmente un po ‘in ritardo nella giornata, ma se si utilizza la libreria FluentAssertions , allora ha asserzioni personalizzate per serializzazione XML, serializzazione binaria e serializzazione del contratto dati.

 theObject.Should().BeXmlSerializable(); theObject.Should().BeBinarySerializable(); theObject.Should().BeDataContractSerializable(); theObject.Should().BeBinarySerializable( options => options.Excluding(s => s.SomeNonSerializableProperty));