Pokus
Pokus

Reputation: 11763

How to unit test if my object is really serializable?

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

Answers (7)

David Keaveny
David Keaveny

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

erikkallen
erikkallen

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

GeverGever
GeverGever

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

Zaid Masud
Zaid Masud

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

Patrick Desjardins
Patrick Desjardins

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

Scott Weinstein
Scott Weinstein

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

Steven A. Lowe
Steven A. Lowe

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

Related Questions