Есть ли какая-либо сериализация тестирования единицы измерения?

У меня есть класс, который сериализует набор объектов (с использованием сериализации XML), которые я хочу использовать unit test.

Моя проблема заключается в том, что мне кажется, что я буду тестировать реализацию XML-сериализации XML, а не что-нибудь полезное. У меня также есть небольшой сценарий курица и яйцо, где, чтобы протестировать Reader, мне понадобится файл, созданный Writer, чтобы сделать это.

Я думаю, что вопросы (там 3, но все они относятся) Я в конечном счете ищут обратную связь:

  • Возможно ли протестировать Writer без использования Reader?
  • Какая лучшая стратегия для тестирования читателя (файл XML? Mocking with record/playback)? Это то, что все, что вы действительно будете делать, это тестирование значений свойств объектов, которые были десериализованы?
  • Какая лучшая стратегия для тестирования писателя!

Фоновая информация о сериализации Xml

Я не использую схему, поэтому все элементы и атрибуты XML соответствуют свойствам объектов. Поскольку нет схемы, теги/атрибуты, которые не соответствуют свойствам, найденным в свойствах каждого объекта, просто игнорируются XmlSerializer (поэтому значение свойства равно null или по умолчанию). Вот пример

<MyObject Height="300">
    <Name>Bob</Name>
    <Age>20</Age>
<MyObject>

будет отображаться на

public class MyObject
{
  public string Name { get;set; }
  public int Age { get;set; }

  [XmlAttribute]
  public int Height { get;set; }
}

и наоборот. Если объект изменился на ниже, XML все равно будет десериализоваться успешно, но FirstName будет пустым.

public class MyObject
{
  public string FirstName { get;set; }
  public int Age { get;set; }

  [XmlAttribute]
  public int Height { get;set; }
}

Недопустимый XML файл будет десериализован правильно, поэтому unit test пройдет, если вы не выполнили утверждения о значениях MyObject.

Ответы

Ответ 1

Я бы сказал, что важно unit test сериализация , если, жизненно важно, чтобы вы могли читать данные между версиями. И вы должны протестировать "известные хорошие" данные (т.е. Недостаточно просто написать данные в текущей версии, а затем прочитать их снова).

Вы упомянули, что у вас нет схемы... почему бы не создать ее? Либо вручную (это не очень сложно), либо с помощью xsd.exe. Затем у вас есть что-то использовать в качестве шаблона, и вы можете проверить это, используя XmlReader. На данный момент я много работаю с сериализацией xml, и гораздо проще обновить схему, чем беспокоиться о том, правильно ли я получаю данные.

Даже XmlSerializer может быть сложным; особенно если вы включаете подклассы ([XmlInclude]), настраиваемую сериализацию (IXmlSerializable) или конструкцию XmlSerializer, отличную от по умолчанию (передача дополнительных метаданных во время выполнения в ctor). Другая возможность - творческое использование [XmlIngore], [XmlAnyAttribute] или [XmlAnyElement]; например, вы можете поддерживать неожиданные данные для однократного (только) в версии X, но хранить его в известном свойстве в версии Y.


С сериализации вообще:

Причина проста: вы можете разбить данные! Как сильно вы это делаете, зависит от сериализатора; например, с BinaryFormatter (и я знаю, что вопрос XmlSerializer), просто меняя с:

public string Name {get;set;}

к

private string name;
public string Name {
    get {return name;}
    set {name = value; OnPropertyChanged("Name"); }
}

может быть достаточно, чтобы прервать сериализацию, поскольку имя поля изменилось (и BinaryFormatter любит поля).

Существуют и другие случаи, когда вы можете случайно переименовать данные (даже в сериализаторах на основе контрактов, таких как XmlSerializer/DataContractSerializer). В таких случаях вы обычно можете переопределять идентификаторы проводов (например, [XmlAttribute("name")] и т.д.), Но важно проверить это!

В конечном счете, это сводится к: важно ли вы читать старые данные? Обычно это; поэтому не просто отправьте его... доказать, что вы можете.

Ответ 2

Вам нужно иметь возможность сделать обратную совместимость? Если это так, возможно, стоит собрать модульные тесты файлов, созданных старыми версиями, которые все еще могут быть десериализованы новыми версиями.

Кроме того, если вы когда-либо представляете что-либо "интересное", возможно, стоит unit test просто проверить, что вы можете сериализовать и десериализовать, чтобы убедиться, что вы не делаете что-то напуганное с использованием свойства readonly и т.д.

Ответ 3

Для меня это абсолютно в категории "Не беспокоить". Я не unit test мои инструменты. Однако, если вы написали свой собственный класс сериализации, то, во всяком случае, unit test он.

Ответ 4

Если вы хотите, чтобы сериализация ваших объектов не прерывалась, тогда, во всяком случае, unit test. Если вы прочитали документы MSDN для класса XMLSerializer:

XmlSerializer не может сериализовать или десериализовать следующее:

Массивы ArrayList
Массивы списка <T>

Существует также особая проблема с перечислениями, объявленными как unsigned longs. Кроме того, любые объекты, помеченные как [Obsolete], не будут сериализованы с .Net 3.5 и далее.

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

По сути, вы не являетесь модульным тестированием XML-сериализации, вы проверяете, что ваши объекты могут быть сериализованы. То же самое относится к десериализации.

Ответ 5

Да, до тех пор, пока то, что нужно протестировать, проверено надлежащим образом, через небольшое вмешательство.

Тот факт, что вы сериализуете и десериализируете в первую очередь, означает, что вы, вероятно, обмениваетесь данными с "внешним миром" - миром вне домена сериализации .NET. Поэтому ваши тесты должны иметь аспект, который находится за пределами этого домена. Неверно проверять Writer с помощью Reader, и наоборот.

Это не только о том, закончите ли вы тестирование сериализации/десериализации .NET; вы должны проверить свой интерфейс с внешним миром - вы можете выводить XML в ожидаемом формате и что вы можете правильно использовать XML в ожидаемом формате.

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

Предположим, что вы отдаете задание заметок и читаете заметки одному и тому же парню:

You - Bob, I want you to jot down the following: "small yellow duck."
Bob - OK, got it.
You - Now, read it back to me.
Bob - "small yellow duck"

Теперь, что мы тестировали здесь? Может ли Боб действительно написать? Боб даже написал что-нибудь или он запомнил слова? Может ли Боб действительно читать? - собственный почерк? Как насчет другого человека почерк? У нас нет ответов ни на один из этих вопросов.

Теперь представим Алису картинку:

You - Bob, I want you to jot down the following: "small yellow duck."
Bob - OK, got it.
You - Alice, can you please check what Bob wrote?
Alice - OK, he got it.
You - Alice, can you please jot down a few words?
Alice - Done.
You - Bob, can you please read them?
Bob - "red fox"
Alice - Yup, that sounds right.

Теперь мы с уверенностью знаем, что Боб может писать и читать правильно - пока мы полностью можем доверять Алисе. Статические данные XML (идеально протестированные против схемы) должны быть достаточно надежными.

Ответ 6

По моему опыту это определенно стоит, особенно если XML будет использоваться в качестве XML-документа для потребителя. Например, потребителю может потребоваться, чтобы каждый элемент присутствовал в документе, чтобы избежать нулевой проверки узлов при обходе или для проверки схемы.

По умолчанию XML-сериализатор будет пропускать свойства с нулевым значением, если вы не добавите атрибут [XmlElement (IsNullable = true)]. Аналогично, вам может потребоваться перенаправить свойства общего списка на стандартные массивы с атрибутом XMLArray.

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

Итак, для чего-либо, кроме тривиального использования, или если вышеприведенные соображения не имеют значения, стоит усилий по его тестированию.

Ответ 7

Существует много типов, с которыми сериализация не может справиться и т.д. Также, если у вас есть неправильные атрибуты, обычно возникает исключение при попытке прочитать xml.

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

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

Как говорили другие люди, если вам нужно иметь возможность читать данные, сохраненные старыми версиями вашего программного обеспечения, вам лучше хранить набор файлов данных примера для каждой отправленной версии и иметь тесты, подтверждающие, что вы все еще можете читать их. Это сложнее, чем кажется на первый взгляд, поскольку значение полей на объекте может меняться между версиями, поэтому просто быть в состоянии создать текущий объект из старого сериализованного файла недостаточно, вы должны проверить, что смысл тот же так как это была версия программного обеспечения, которая сохранила файл. (Поместите атрибут версии в свой корневой объект сейчас!)

Ответ 8

Я согласен с вами в том, что вы будете тестировать реализацию .NET больше, чем будете тестировать свой собственный код. Но если это то, что вы хотите сделать (возможно, вы не доверяете реализации .NET:)), я мог бы подойти к вашим трем вопросам следующим образом.

  • Да, конечно, можно проверить автора без читателя. Используйте сценарист для сериализации примера (20-летний Боб), который вы предоставили MemoryStream. Откройте MemoryStream с помощью XmlDocument. Утверждение root node называется "MyObject". Утверждение имеет один атрибут с именем "Высота" со значением "300". Утверждение есть элемент "Имя", содержащий текст node со значением "Боб". Утверждение есть элемент "Возраст", содержащий текст node со значением "20".

  • Просто выполните обратный процесС# 1. Создайте XmlDocument из 20-летней Bob XML-строки. Удалите поток с помощью считывателя. Утвердить свойство Name равно "Bob". Утвердить свойство Age равно 20. Вы можете сделать что-то вроде добавления тестового примера с незначительными пробелами или одинарными кавычками вместо двойных кавычек, чтобы быть более тщательными.

  • См. № 1. Вы можете расширить его, добавив, что вы считаете сложными "крайними" случаями, которые, по вашему мнению, могут сломать его. Имена с различными символами Юникода. Дополнительные длинные имена. Пустые имена. Отрицательный возраст. Etc.

Ответ 9

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

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

Ответ 10

Мы проводим принятие тестирование нашей сериализации, а не модульное тестирование.

Это означает, что наши тестеры принятия принимают схему XML или, как в вашем случае, образец XML, и повторно создают свой собственный сериализуемый класс передачи данных.

Затем мы используем NUnit для тестирования нашей службы WCF с помощью этого XML-пространства чистой комнаты.

С помощью этой техники мы выявили много и много ошибок. Например, мы изменили имя члена .NET и забыли добавить тег [XmlElement] с свойством Name =.

Ответ 11

Если вы ничего не можете сделать, чтобы изменить способ сериализации класса, то вы тестируете реализацию XML-сериализации XML; -)

Ответ 12

Если формат сериализованного XML имеет значение, вам нужно проверить сериализацию. Если важно, что вы можете десериализовать его, вам нужно протестировать десериализацию.

Ответ 13

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

Говоря об этом, я недавно принял практику, когда я проверяю такие вещи во время компиляции, а не во время выполнения модульных тестов. Это немного утомительно, но у меня есть компонент, который может пересекать AST, а затем я могу прочитать его в шаблоне T4 и написать много сообщений #error, если я встречу что-то, чего не должно быть.