Reputation: 11763
I am using C# 2.0 with Nunit Test. I have some object that needs to be serialized. These objects are quite complex (inheritance at different levels and contains a lot of objects, events and delegates).
How can I create a Unit Test to be sure that my object is safely serializable?
Upvotes: 37
Views: 25266
Reputation: 4079
Probably a bit late in the day, but if you are using the FluentAssertions library, then it has custom assertions for XML serialization, binary serialization, and data contract serialization.
theObject.Should().BeXmlSerializable();
theObject.Should().BeBinarySerializable();
theObject.Should().BeDataContractSerializable();
theObject.Should().BeBinarySerializable<MyClass>(
options => options.Excluding(s => s.SomeNonSerializableProperty));
Upvotes: 4
Reputation: 34391
Unfortunately, you can't really test for this. Imagine this case:
[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
}
Upvotes: 1
Reputation: 519
Here is a generic way:
public static Stream Serialize(object source)
{
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
formatter.Serialize(stream, source);
return stream;
}
public static T Deserialize<T>(Stream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Position = 0;
return (T)formatter.Deserialize(stream);
}
public static T Clone<T>(object source)
{
return Deserialize<T>(Serialize(source));
}
Upvotes: 49
Reputation: 13443
Here is a solution that recursively uses IsSerializable to check that the object and all its properties are Serializable.
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);
}
}
Upvotes: 2
Reputation: 140753
I have this in some unit test here at job:
MyComplexObject dto = new MyComplexObject();
MemoryStream mem = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
try
{
b.Serialize(mem, dto);
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
Might help you... maybe other method can be better but this one works well.
Upvotes: 17
Reputation: 19117
In addition to the test above - which makes sure the serializer will accept your object, you need to do a round-trip test. Deserialize the results back to a new object and make sure the two instances are equivalent.
Upvotes: 16
Reputation: 61223
serialize the object (to memory or disk), deserialize it, use reflection to compare the two, then run all of the unit tests for that object again (except serialization of course)
this assumes that your unit tests can accept an object as a target instead of making their own
Upvotes: 2