Как выполнить юнит-тест, если мой объект действительно сериализуем?

Я использую C# 2.0 с Nunit Test. У меня есть объект, который нужно сериализовать. Эти объекты довольно сложны (наследование на разных уровнях и содержит много объектов, событий и делегатов).

Как я могу создать модульный тест, чтобы убедиться, что мой объект безопасно сериализуем?

7 ответов

Решение

У меня есть это в каком-то модульном тесте здесь на работе:

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

Может помочь вам... может быть, другой метод может быть лучше, но этот работает хорошо.

Вот общий способ:

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

В дополнение к описанному выше тесту, который гарантирует, что сериализатор примет ваш объект, вам необходимо выполнить тестирование в оба конца. Десериализовать результаты обратно в новый объект и убедиться, что два экземпляра эквивалентны.

Возможно, немного поздно в этот день, но если вы используете библиотеку FluentAssertions, то у нее есть пользовательские утверждения для сериализации XML, двоичной сериализации и сериализации контракта данных.

theObject.Should().BeXmlSerializable();
theObject.Should().BeBinarySerializable();
theObject.Should().BeDataContractSerializable();

theObject.Should().BeBinarySerializable<MyClass>(
    options => options.Excluding(s => s.SomeNonSerializableProperty));

Сериализовать объект (в память или на диск), десериализовать его, использовать отражение, чтобы сравнить два, затем снова запустить все модульные тесты для этого объекта (кроме, конечно, сериализации)

это предполагает, что ваши юнит-тесты могут принять объект в качестве цели вместо того, чтобы делать свои собственные

Вот решение, которое рекурсивно использует IsSerializable, чтобы проверить, что объект и все его свойства являются Сериализуемыми.

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

К сожалению, вы не можете действительно проверить это. Представьте себе этот случай:

[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
}
Другие вопросы по тегам