Как unit test, если мой объект действительно сериализуем?

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

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

Ответ 1

У меня это в некотором unit test здесь, на задании:

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

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

Вот решение, которое рекурсивно использует IsSerializable для проверки того, что объект и все его свойства являются 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);
        }
    }

Ответ 6

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

[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
}

Ответ 7

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

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

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