2009-07-09 21 views
14

Tengo una clase que serializa un conjunto de objetos (usando la serialización XML) que quiero probar en una unidad.¿Hay algún punto de serialización de prueba de la unidad?

Mi problema es que parece que voy a probar la implementación .NET de la serialización XML, en lugar de algo útil. También tengo un pequeño escenario de huevo y pollo donde para probar el Reader, necesitaré un archivo producido por el escritor para hacerlo.

creo que las preguntas (hay 3 pero todos ellos están relacionados) Estoy en última instancia, en busca de comentarios sobre el contenido son:

  1. ¿Es posible probar el escritor, sin utilizar el lector?
  2. ¿Cuál es la mejor estrategia para probar el lector (archivo XML? ¿Mocking con grabación/reproducción)? ¿Es el caso que todo lo que realmente estarás haciendo es probar los valores de las propiedades de los objetos que se han deserializado?
  3. ¿Cuál es la mejor estrategia para probar al escritor?

información de antecedentes sobre la serialización XML

no estoy usando un esquema, por lo que todos los elementos y atributos XML coincide con las propiedades de los objetos. Como no hay esquema, las etiquetas/atributos que no coinciden con las que se encuentran en las propiedades de cada objeto, simplemente son ignoradas por XmlSerializer (por lo que el valor de la propiedad es nulo o predeterminado). Aquí está un ejemplo

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

sería asignar a

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

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

y viceversa. Si el objeto cambia al siguiente, el XML aún se deserializaría correctamente, pero FirstName estaría en blanco.

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

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

Un archivo XML no válido sería deserializar correctamente, por lo tanto, la prueba de la unidad pasaría a menos que ejecutara las afirmaciones sobre los valores de la MiObjeto.

Respuesta

19

Yo diría que es esencial para la serialización de prueba unitaria si es es de vital importancia que pueda leer datos entre versiones. Y usted debe probar con datos "bien conocidos" (es decir, no es suficiente simplemente escribir datos en la versión actual y luego leerlos nuevamente).

Menciona que no tiene un esquema ... ¿por qué no generar uno? Ya sea a mano (no es muy difícil), o con xsd.exe. Luego tiene algo que usar como plantilla, y puede verificar esto simplemente usando XmlReader. Estoy haciendo un lote de trabajo con serialización xml en este momento, y es mucho más fácil actualizar el esquema que preocuparme si obtengo los datos correctos.

Incluso XmlSerializer puede ser complejo; particularmente si involucra subclases ([XmlInclude]), serialización personalizada (IXmlSerializable) o construcción no predeterminada XmlSerializer (pasando metadatos adicionales en tiempo de ejecución al controlador).Otra posibilidad es el uso creativo de [XmlIngore], [XmlAnyAttribute] o [XmlAnyElement]; Por ejemplo, puede soportar datos inesperados para la ida y vuelta (sólo) en la versión X, pero almacenarlo en una propiedad conocida en la versión Y.


Con la serialización en general:

La razón es simple: ¡puedes romper los datos! Lo mal que lo haga depende del serializador; por ejemplo, con BinaryFormatter (y sé que la pregunta es XmlSerializer), un simple cambio de:

public string Name {get;set;} 

a

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

podría ser enough to break serialization, como el nombre del campo ha cambiado (y BinaryFormatter ama campos) .

Hay otras ocasiones en las que accidentalmente puede cambiar el nombre de los datos (incluso en serializadores basados ​​en contrato como XmlSerializer/DataContractSerializer). En tales casos, generalmente puede anular los identificadores de cable (por ejemplo, [XmlAttribute("name")], etc.), pero es importante verificar esto.

En última instancia, todo se reduce a: ¿es importante que pueda leer datos antiguos? Por lo general es; así que no lo envíe ... pruebe que pueda.

+0

Originalmente tenía un esquema, y ​​la lectura + escritura fue realizada por mi propia clase que escribió el gráfico de objetos. Entonces (¡1 año después!) Descubrí que todo el trabajo podría haber sido realizado por XmlSerializer. En términos de compatibilidad con versiones anteriores, diría que el XML estaría vinculado a la versión de ensamblaje con la que fue escrito. Entonces, si le dio a la última versión del ensamblado algunos XML producidos por versiones anteriores, existe la posibilidad de que el modelo de objetos haya cambiado, por lo que ya no coincide. No estoy seguro de que esto ocurra alguna vez, pero no veo cómo (continúa) –

+0

se deserializaría un formato anterior (como lo menciona Jon) sin que siempre se rompa y tenga que realizarlo manualmente con un XmlReader? –

+0

XmlSerializer elimina datos inesperados sin error, o puede usar '[XmlAny *]' - por lo que hay formas de * parcialmente * deserializar un objeto (y obtener los otros datos de los "cualesquiera" accesorios). –

7

Para mí, esto está absolutamente en la categoría No molestar. Yo no pruebo las herramientas por mi cuenta. Sin embargo, si usted escribió su propia clase de serialización, entonces por supuesto la unidad lo prueba.

26

¿Necesita poder hacer la retrocompatibilidad? Si es así, puede valer la pena construir pruebas unitarias de archivos producidos por versiones anteriores que aún podrían ser deserializadas por nuevas versiones.

Aparte de eso, si alguna vez se introduce nada "interesante" que puede ser digno de una unidad de prueba a sólo echa puede serializar y deserializar sólo para asegurarse de que no estás haciendo algo funky con una propiedad de sólo lectura, etc.

+1

Podríamos agregar y eliminar (hojas) las propiedades en el futuro, pero no cambiará drásticamente –

+3

Yo diría que todavía es un cambio suficiente para que valga la pena probar. –

0

Si no hay nada que pueda hacer para cambiar la forma de su clase serializa, a continuación, que está probando la aplicación de la serialización XML ;-)

0

Si el formato de los asuntos XML serializados de .NET, entonces usted necesita para poner a prueba la serialización. Si es importante que puedas deserializarlo, entonces debes probar la deserialización.

5

Si desea asegurarse de que la serialización de sus objetos no se rompa, entonces, por supuesto, pruebe la unidad.Si usted lee la documentación de MSDN para la clase XMLSerializer:

XmlSerializer no puede serializar o deserializar los siguientes:

matrices de ArrayList
matrices de Lista <T>

También hay un problema peculiar con enumerados declarados como largos sin firmar. Además, los objetos marcados como [Obsolete] no se serializan desde .Net 3.5 en adelante.

Si tiene un conjunto de objetos que se serializan, probar la serialización puede parecer extraño, pero solo se necesita que alguien edite los objetos que se serializan para incluir una de las condiciones no soportadas para la serialización.

En efecto, no está probando la serialización de XML de unidad, está probando que sus objetos se pueden serializar. Lo mismo aplica para la deserialización.

0

ver cómo realmente no se puede fijar serialización, no deberías de probarlo - en su lugar, usted debe estar probando su propio código y la forma en que interactúa con el mecanismo de serialización. Por ejemplo, puede que necesite probar la estructura de los datos que está serializando para asegurarse de que nadie cambie accidentalmente un campo o algo así.

Hablando de eso, recientemente he adoptado una práctica donde verifico tales cosas en en tiempo de compilación en lugar de durante la ejecución de pruebas unitarias. Es un poco tedioso, pero tengo un componente que puede atravesar el AST, y luego puedo leerlo en una plantilla T4 y escribir muchos mensajes #error si encuentro algo que no debería estar allí.

+0

Lo siento, es totalmente erróneo. Puede influir en gran medida en muchos detalles de la serialización XML agregando atributos a las clases que se serializan. –

+1

Podría ser una cuestión de interpretación, pero para mí probar "la forma en que * interactúa * con el mecanismo de serialización" incluye probar que los atributos que ha implementado funcionan de la manera que usted piensa. No está probando si una propiedad puede ser serializada, está probando si su configuración de ** esta propiedad ** se ha configurado correctamente. – Bevan

1

he hecho esto en algunos casos ... no probar la serialización como tal, pero utilizando algunas serializaciones XML 'buena conocidos' y luego cargarlos en mis clases, y comprobar que todas las propiedades (según corresponda) tienen la Valores esperados.

Esto no va a probar nada para la primera versión de ... pero si las clases evolucionan, sé que detectaré cualquier cambio en el formato.

2

En mi experiencia, definitivamente vale la pena hacerlo, especialmente si el XML va a ser utilizado como un documento XML por el consumidor. Por ejemplo, el consumidor puede necesitar tener todos los elementos presentes en el documento, ya sea para evitar la verificación nula de los nodos al atravesar o para pasar la validación del esquema.

De forma predeterminada, el serializador XML omitirá las propiedades con un valor nulo a menos que agregue el atributo [XmlElement (IsNullable = true)]. Del mismo modo, es posible que tenga que redirigir las propiedades de la lista genérica a las matrices estándar con un atributo XMLArray.

Como dijo otro colaborador, si el objeto cambia con el tiempo, debe comprobar continuamente que la salida sea coherente. También lo protegerá contra el cambio de serializador y no será compatible con versiones anteriores, aunque es de esperar que esto no suceda.

Así que para cualquier cosa que no sean triviales, o cuando las consideraciones anteriores son irrelevantes, vale la pena el esfuerzo de probarlas por unidad.

2

Hay muchos tipos que la serialización no puede manejar, etc. Además, si tiene sus atributos incorrectos, es común obtener una excepción cuando intenta leer el xml.

Tiendo a crear un árbol de ejemplo de los objetos que se pueden serializar con al menos un ejemplo de cada clase (y subclase). Luego, como mínimo, serialice el árbol de objetos en una secuencia de cadenas y luego vuelva a leerlo desde la secuencia de cadenas.

Se sorprenderá de la cantidad de veces que esto presenta un problema y me ahorrará tener que esperar a que la aplicación se inicie para encontrar el problema. Este nivel de pruebas unitarias se trata más de acelerar el desarrollo en lugar de aumentar la calidad, por lo que no lo haría para la serialización de trabajo.

Como han dicho otras personas, si necesita poder leer los datos guardados por versiones anteriores de su software, es mejor que mantenga un conjunto de archivos de datos de ejemplo para cada versión enviada y tenga pruebas para confirmar que todavía puede léalosEsto es más difícil de lo que parece al principio, ya que el significado de los campos de un objeto puede cambiar de una versión a otra, por lo que no basta con crear el objeto actual a partir de un archivo antiguo serializado, debes verificar que el significado sea el mismo como lo era la versión del software que guardó el archivo. (¡Ponga ahora un atributo de versión en su objeto raíz!)

2

Estoy de acuerdo con usted en que probará la implementación de .NET más de lo que estará probando su propio código. Pero si eso es lo que quieres hacer (quizás no confíes en la implementación de .NET :)), podría abordar tus tres preguntas de la siguiente manera.

  1. Sí, sin duda es posible probar al escritor sin el lector. Utilice el escritor para serializar el ejemplo (Bob de 20 años) que proporcionó a un MemoryStream. Abra el MemoryStream con un XmlDocument. Afirma que el nodo raíz se llama "MyObject". Afirma que tiene un atributo llamado "Altura" con el valor "300". Afirma que hay un elemento "Nombre" que contiene un nodo de texto con el valor "Bob". Afirma que hay un elemento "Edad" que contiene un nodo de texto con el valor "20".

  2. Simplemente haga el proceso inverso de # 1. Crea un XmlDocument a partir de la cadena Bob XML de 20 años. Deserializar la corriente con el lector. La propiedad Assert the Name equivale a "Bob". Afirma que la propiedad Age equivale a 20. Puedes hacer cosas como agregar caso de prueba con espacios en blanco insignificantes o comillas simples en lugar de comillas para ser más exhaustivo.

  3. Ver # 1. Puede ampliarlo añadiendo lo que considera que son casos complicados de "borde" que cree que podrían romperlo. Nombres con varios caracteres Unicode. Nombres extra largos. Nombres vacíos. Edades negativas. Etc.

1

Hacemos aceptación prueba de nuestra serialización en lugar de la unidad de pruebas.

Lo que esto significa es que nuestros evaluadores de aceptación toman el esquema XML, o como en su caso algunos ejemplos de XML, y vuelven a crear su propia clase de transferencia de datos serializable.

Luego utilizamos NUnit para probar nuestro servicio WCF con este XML de sala blanca.

Con esta técnica, hemos identificado muchos, muchos errores. Por ejemplo, donde hemos cambiado el nombre del miembro .NET y olvidado agregar una etiqueta [XmlElement] con una propiedad Name =.

3

Sí, siempre que lo que se necesita probar se pruebe adecuadamente, mediante un poco de intervención.

El hecho de que esté serializando y deserializando en primer lugar significa que probablemente esté intercambiando datos con el "mundo exterior", el mundo fuera del dominio de serialización .NET. Por lo tanto, sus pruebas deben tener un aspecto que está fuera de este dominio. No está bien probar el escritor usando el lector, y viceversa.

No se trata solo de si acabas de terminar probando la serialización/deserialización de .NET; tienes que probar tu interfaz con el mundo exterior, que puedes generar XML en el formato esperado y que puedes consumir XML correctamente en el formato anticipado.

Debe tener datos XML estáticos que se puedan usar para compararlos contra la salida de serialización y para usarlos como datos de entrada para la deserialización.

Supongamos que usted da el trabajo de toma de notas y la lectura de las notas de nuevo a la misma persona:

 
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" 

Ahora bien, ¿qué hemos probado aquí? ¿Puede Bob realmente escribir? ¿ Bob incluso escribió algo o memorizó las palabras? ¿Puede Bob realmente leer? - ¿Su propia letra? ¿Qué pasa con la escritura de otra persona? No tenemos respuestas a ninguna de estas preguntas.

Ahora vamos a introducir Alice a la imagen:

 
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. 

Ahora sabemos, con certeza, que Bob puede escribir y leer correctamente - el tiempo que podemos confiar completamente Alice. Los datos XML estáticos (idealmente contrastados con un esquema) deberían ser lo suficientemente confiables.

Cuestiones relacionadas