Gibt es einen Punkt Unit Testing Serialisierung?

Ich habe eine Klasse, die eine Reihe von Objekten serialisiert (mit XML-Serialisierung), die ich unit testen möchte.

Mein Problem ist, dass es sich anfühlt, als würde ich die .NET-Implementierung der XML-Serialisierung testen, anstatt etwas Nützliches. Ich habe auch ein leichtes Huhn und Ei-Szenario, wo, um den Reader zu testen, werde ich eine Datei vom Writer produziert, um dies zu tun.

Ich denke, die Fragen (es gibt 3, aber sie beziehen sich alle) Ich bin schließlich auf der Suche nach Feedback auf sind:

  1. Ist es möglich, den Writer zu testen, ohne den Reader zu verwenden?
  2. Was ist die beste Strategie zum Testen des Readers (XML-Datei? Spott mit Platte/Wiedergabe)? Ist es so, dass Sie nur die Eigenschaftswerte der Objekte testen, die deserialisiert wurden?
  3. Was ist die beste Strategie, um den Autor zu testen!

Hintergrundinformationen zur Xml-Serialisierung

Ich verwende kein Schema, sodass alle XML-Elemente und -Attribute mit den Eigenschaften der Objekte übereinstimmen. Da es kein Schema gibt, werden Tags/Attribute, die nicht mit denen übereinstimmen, die in den Eigenschaften jedes Objekts gefunden wurden, einfach vom XmlSerializer ignoriert (der Wert der Eigenschaft ist null oder Standardwert). Hier ist ein Beispiel

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

würde Karte zu

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

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

und Visum versa. Wenn das Objekt auf die unten geändert würde die XML-Datei immer noch erfolgreich deserialisieren, aber FirstName wäre leer.

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

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

Eine ungültige XML-Datei würde korrekt deserialisiert, daher würde der Komponententest bestehen, es sei denn, Sie haben Assertionen für die Werte von MyObject ausgeführt.

Antwort auf "Gibt es einen Punkt Unit Testing Serialisierung? " 13 von antworten

Für mich ist dies absolut in der Kategorie Don't Bother. Ich teste meine Werkzeuge nicht einfach. Wenn Sie jedoch Ihre eigene Serialisierungsklasse geschrieben haben, dann testen Sie sie auf jeden Fall.

Müssen Sie in der Lage sein, Abwärtskompatibilität zu tun? Wenn ja, kann es sich lohnen, Komponententests von Dateien zu erstellen, die von alten Versionen produziert wurden und die noch durch neue Versionen deserialisiert werden sollten.

Ansonsten, wenn Sie jemals etwas "interessantes" einführen, kann es einen Komponententest wert sein, um nur zu überprüfen, ob Sie serialisieren und deserialisieren können, nur um sicherzustellen, dass Sie nicht etwas Funky mit einer schreibgeschützten Eigenschaft usw. tun.

Wenn Es nichts gibt, was Sie tun können, um die Art und Weise zu ändern, wie Ihre Klasse serialisiert wird, dann testen Sie . NET-Implementierung der XML-Serialisierung ;-)

Wenn das Format des serialisierten XML wichtig ist, dann müssen Sie die Serialisierung testen. Wenn es wichtig ist, dass Sie es deserialisieren können, müssen Sie die Deserialisierung testen.

Wenn Sie sicherstellen möchten, dass die Serialisierung Ihrer Objekte nicht bricht, dann auf jeden Fall Komponententest. Wenn Sie die MSDN-Dokumente für die XMLSerializer class: Klasse lesen:

Der XmlSerializer kann Folgendes nicht serialisieren oder deserialisieren:

Arrays von ArrayList
Arrays von List<T>

Es gibt auch ein seltsames Problem mit Enumerationen, die als nicht signierte Longs deklariert sind. Darüber hinaus werden Objekte, die als [Obsolete] do no get serialized from .Net 3.5 onwards. markiert sind, nicht ab .Net 3.5 serialisiert.

Wenn Sie über eine Reihe von Objekten verfügen, die serialisiert werden, mag das Testen der Serialisierung seltsam erscheinen, aber es dauert nur jemanden, der die serialisierten Objekte bearbeitet, um eine der nicht unterstützten Bedingungen für die Serialisierung einzuschließen.

Im Faktisten testen Sie keine Komponententests für die XML-Serialisierung, sondern testen, ob Ihre Objekte serialisiert werden können. Dasselbe gilt für die Deserialisierung.

Wenn man sieht, wie man die Serialisierung nicht wirklich beheben kann, sollte man ihn nicht testen, sondern seinen eigenen Code testen und wie er mit dem Serialisierungsmechanismus interagiert. Sie müssen z. B. die Struktur der Daten, die Sie serialisieren, komponententesten, um sicherzustellen, dass niemand versehentlich ein Feld oder etwas ändert.

Apropos, ich habe vor kurzem eine Praxis angenommen, in der ich solche Dinge bei Kompilierungszeit und nicht während der Durchführung von Komponententests prüfe. Es ist ein bisschen mühsam, aber ich habe eine Komponente, die die AST durchlaufen kann, und dann kann ich sie in einer T4-Vorlage lesen und viele #error messages if I meet something that shouldn't be there. Nachrichten schreiben, wenn ich etwas treffe, das nicht da sein sollte.

Habe ich das in einigen Fällen getan... nicht die Serialisierung als solche testen, sondern einige "bekannte gute" XML-Serialisierungen verwenden und dann in meine Klassen laden und überprüfen, ob alle Eigenschaften (sofern zutreffend) die erwarteten Werte aufweisen.

Dies wird nichts für die erste Version testen... aber wenn sich die Klassen jemals weiterentwickeln, weiß ich, dass ich alle brechenden Änderungen im Format erwischen werde.

Ich würde argumentieren, dass es wichtig ist, die Serialisierung zu testen, wenn es von entscheidender Bedeutung ist, dass Sie Daten zwischen Versionen lesen können. Und Sie müssen mit "bekannten guten" Daten testen (d.h. es reicht nicht aus, einfach Daten in der aktuellen Version zu schreiben und dann wieder zu lesen).

Sie erwähnen, dass Sie kein Schema haben... warum nicht eine generieren? Entweder von Hand (es ist nicht sehr schwer), oder mit xsd.exe. Then you have something to use as a template, and you can verify this just using . Dann haben Sie etwas als Vorlage zu verwenden, und Sie können dies nur mit XmlReader. I'm doing a überprüfen. Ich mache ein Los der Arbeit mit XML-Serialisierung im Moment, und es ist viel einfacher, das Schema zu aktualisieren, als sich Gedanken darüber zu machen, ob ich die Daten richtig bekomme.

Auch XmlSerializer can get complex; particularly if you involve subclasses ( kann komplex werden; insbesondere, wenn Sie Unterklassen ( [XmlInclude]), custom serialization ( ), benutzerdefinierte Serialisierung ( IXmlSerializable), or non-default ) oder nicht standardmäßige XmlSerializer construction (passing additional metadata at runtime to the ctor). Another possibility is creative use of -Konstruktion (Übergeben zusätzlicher Metadaten zur Laufzeit an den ctor) einbeziehen. Eine weitere Möglichkeit ist die kreative Nutzung von [XmlIngore], , [XmlAnyAttribute] or oder [XmlAnyElement]; for example you might support unexpected data for round-trip (only) in version X, but store it in a known property in version Y. ; Sie können z. B. unerwartete Daten für Roundtrip (nur) in Version X unterstützen, diese jedoch in einer bekannten Eigenschaft in Version Y speichern.


Mit Serialisierung im Allgemeinen:

Der Grund ist einfach: Sie können die Daten brechen! Wie schlecht Sie dies tun, hängt vom Serialisierer ab; zum Beispiel mit BinaryFormatter (and I know the question is (und ich weiß, die Frage ist XmlSerializer), simply changing from: ), einfach von:

public string Name {get;set;}

zu

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

ändern könnte enough to break serialization, as the field name has changed (and BinaryFormatter loves fields). loves fields). sein, da sich der Feldname geändert hat (und BinaryFormatter loves fields). liebt Felder).

Es gibt andere Fälle, in denen Sie die Daten versehentlich umbenennen können (auch in vertragsbasierten Serialisierern wie XmlSerializer / / DataContractSerializer). In such cases you can usually override the wire identifiers (for example ). In solchen Fällen können Sie in der Regel die Drahtbezeichner überschreiben (z.B. [XmlAttribute("name")] etc), but it is important to check this! usw.), aber es ist wichtig, dies zu überprüfen!

Letztlich kommt es darauf an: Ist es wichtig, dass Sie alte Daten lesen können? Es ist in der Regel; also versenden Sie es nicht einfach... beweisen , dass Sie können.

Meiner Erfahrung nach lohnt es sich auf jeden Fall zu tun, vor allem, wenn das XML vom Consumer als XML-Dokument verwendet wird. Beispielsweise muss der Consumer möglicherweise jedes Element im Dokument vorhanden haben, um entweder eine Nullprüfung von Knoten beim Durchlaufen zu vermeiden oder die Schemaüberprüfung zu bestehen.

Standardmäßig lässt der XML-Serialisierungsmodul Eigenschaften mit einem NULL-Wert weg, es sei denn, Sie fügen das Attribut [XmlElement(IsNullable = true)] hinzu. Auf ähnliche Weise müssen Sie generische Listeneigenschaften an Standardarrays mit einem XMLArray-Attribut umleiten.

Wie ein anderer Mitwirkender sagte, müssen Sie, wenn sich das Objekt im Laufe der Zeit ändert, kontinuierlich überprüfen, ob die Ausgabe konsistent ist. Es wird Sie auch davor schützen, dass sich der Serialisierer selbst ändert und nicht abwärtskompatibel ist, obwohl Sie hoffen, dass dies nicht geschieht.

Also für alles andere als triviale Verwendungen, oder wenn die oben genannten Überlegungen irrelevant sind, lohnt es sich, die Einheit zu testen.

Es gibt viele Typen, mit denen Serialisierung nicht zurechtkommt usw. Auch wenn Ihre Attribute falsch sind, ist es üblich, eine Ausnahme zu erhalten, wenn Sie versuchen, die XML-Datei zurückzulesen.

Ich neige dazu, eine Beispielstruktur der Objekte zu erstellen, die mit mindestens einem Beispiel für jede Klasse (und Unterklasse) serialisiert werden können. Serialisieren Sie dann mindestens die Objektstruktur in einen Stringstream, und lesen Sie sie dann aus dem Stringstream zurück.

Sie werden erstaunt sein, wie viele Zeit dies ein Problem fängt und mich ersparen muss, dass ich warten muss, bis die Anwendung gestartet wird, um das Problem zu finden. Bei diesem Niveau der Komponententests geht es eher darum, die Entwicklung zu beschleunigen, als die Qualität zu erhöhen, also würde ich es nicht für die laufende Serialisierung tun.

Wie andere Leute gesagt haben, wenn Sie in der Lage sein müssen, Daten, die von alten Versionen Ihrer Software gespeichert wurden, zurücklesen zu können, sollten Sie besser eine Reihe von Beispieldatendateien für jede ausgelieferte Version aufbewahren und Tests haben, um zu bestätigen, dass Sie sie immer noch lesen können. Dies ist schwieriger, als es scheint zunächst, da die Bedeutung von Feldern auf einem Objekt zwischen Versionen ändern kann, so dass nur in der Lage, das aktuelle Objekt aus einer alten serialisierten Datei zu erstellen ist nicht genug, müssen Sie überprüfen, ob die Bedeutung ist die gleiche wie es war die Version der Software, die die Datei gespeichert. (Setzen Sie jetzt ein Versionsattribut in Ihr Stammobjekt ein!)

Ich stimme Ihnen zu, dass Sie die .NET-Implementierung mehr testen werden, als Dass Sie Ihren eigenen Code testen werden. Aber wenn Sie dies tun möchten (vielleicht vertrauen Sie der .NET-Implementierung nicht :) ), kann ich Ihre drei Fragen wie folgt angehen.

  1. Ja, es ist sicherlich möglich, den Schreiber ohne den Leser zu testen. Verwenden Sie den Writer, um das Beispiel (20-jähriger Bob) zu serialisieren, das Sie einem MemoryStream zur Verfügung gestellt haben. Öffnen Sie MemoryStream mit einem XmlDocument. Bestätigen Sie, dass der Stammknoten den Namen "MyObject" trägt. Bestätigen Sie, dass es ein Attribut mit dem Namen "Height" mit dem Wert "300" hat. Bestätigen Sie, dass es ein "Name"-Element gibt, das einen Textknoten mit dem Wert "Bob" enthält. Bestätigen Sie, dass es ein "Age"-Element gibt, das einen Textknoten mit dem Wert "20" enthält.

  2. Machen Sie einfach den umgekehrten Prozess der #1. Erstellen Sie ein XmlDocument aus der 20 Jahre alten Bob XML-Zeichenfolge. Deserialisieren Sie den Stream mit dem Reader. Assert die Name-Eigenschaft gleich "Bob". Assert die Age-Eigenschaft entspricht 20. Sie können Z. B. Testfall mit unbedeutendem Leerzeichen oder einfache Anführungszeichen anstelle von doppelten Anführungszeichen hinzufügen, um gründlicher zu sein.

  3. Siehe #1. Sie können es erweitern, indem Sie hinzufügen, was Sie als knifflige "Rand"-Fälle betrachten, von denen Sie denken, dass sie sie brechen könnten. Namen mit verschiedenen Unicode-Zeichen. Extra lange Namen. Leere Namen. Negative Senkalter. Etc.

Wir führen Akzeptanz Tests unserer Serialisierung statt Komponententests durch.

Das bedeutet, dass unsere Akzeptanztester das XML-Schema oder wie in Ihrem Fall einige XML-Beispiele verwenden und ihre eigene serialisierbare Datenübertragungsklasse neu erstellen.

Wir verwenden dann NUnit, um unseren WCF-Service mit diesem Reinraum-XML zu testen.

Mit dieser Technik haben wir viele, viele Fehler identifiziert. Wenn wir z. B. den Namen des .NET-Mitglieds geändert und vergessen haben, ein [XmlElement] tag with a -Tag mit einer Name = property.-Eigenschaft hinzuzufügen.

Ja, solange das, was getestet werden muss, richtig getestet wird, durch ein wenig Intervention.

Die Tatsache, dass Sie in erster Linie serialisieren und deserialisieren, bedeutet, dass Sie wahrscheinlich Daten mit der "Außenwelt" austauschen -- der Welt außerhalb der .NET Serialisierungsdomäne. Daher sollten Ihre Tests einen Aspekt haben, der sich außerhalb dieser Domäne befindet. Es ist nicht in Ordnung, den Writer mit dem Reader zu testen und umgekehrt.

Es geht nicht nur darum, ob Sie am Ende nur die .NET Serialisierung/Deserialisierung testen würden; Sie müssen Ihre Schnittstelle mit der Außenwelt testen – dass Sie XML im erwarteten Format ausgeben können und dass Sie XML im erwarteten Format richtig verwenden können.

Sie sollten über statische XML-Daten verfügen, die verwendet werden können, um mit der Serialisierungsausgabe zu vergleichen und als Eingabedaten für die Deserialisierung zu verwenden.

Angenommen, Sie geben die Aufgabe der Notiz nehmen und lesen Sie die Notizen zurück an den gleichen Kerl:

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"

Nun, was haben wir hier getestet? Kann Bob wirklich schreiben? Hat Bob überhaupt etwas geschrieben oder hat er sich die Worte auswendig gemacht? Kann Bob eigentlich lesen? -- seine eigene Handschrift? Was ist mit der Handschrift einer anderen Person? Wir haben keine Antworten auf diese Fragen.

Nun stellen wir Alice das Bild vor:

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's 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.

Wir wissen jetzt mit Sicherheit, dass Bob und richtig lesen kann -- solange wir Alice vollkommen vertrauen können. Statische XML-Daten (idealerweise anhand eines Schemas getestet) sollten ausreichend vertrauenswürdig sein.