Как выполнить юнит-тест, если мой объект действительно сериализуем? - PullRequest
33 голосов
/ 25 октября 2008

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

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

Ответы [ 7 ]

45 голосов
/ 25 октября 2008

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

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));
}
15 голосов
/ 25 октября 2008

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

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

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

14 голосов
/ 25 октября 2008

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

3 голосов
/ 25 октября 2008

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

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

2 голосов
/ 01 ноября 2010

Вот решение, которое рекурсивно использует 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);
        }
    }
1 голос
/ 03 июля 2017

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

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

theObject.Should().BeBinarySerializable<MyClass>(
    options => options.Excluding(s => s.SomeNonSerializableProperty));
1 голос
/ 16 декабря 2010

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

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