2011-07-13 21 views
5

Estoy escribiendo pruebas de unidades para mi aplicación de griales, y me di cuenta de que realmente no sé la forma correcta de afirmar si un objeto es el adecuado o no.Forma correcta de comparar objetos en una prueba de unidad

Por ejemplo, dada la siguiente prueba:

void testExampleTest() { 
    mockSession.person = new Person(firstName:'John', lastName:'Doe', middleInitial:'E') 
    def model = controller.testMethod() 
    ...assertions... 
} 

y

def testMethod = { 
    Person currPerson = session.getAttribute("person") 
    render(view:'view',model:[person:currPerson] 
} 

¿Cómo debo asegurarse de que el objeto persona añadí a la sesión correctamente se está pasando en el modelo? ¿Es suficiente usar

assertEquals(person,model['person']) 

o porque Inyecté el objeto a mí mismo en la sesión no tiene más sentido utilizar

assertEquals(person.firstName, model['person'].firstName) 
assertEquals(person.lastName, model['person'].lastName) 
assertequals(person.middleName, model['person'].middleName) 

Me parece que la primera forma debería ser suficiente siempre y cuando el objeto tiene un método equals correctamente definido, pero solo quería ver cuál es la forma convencional.

Gracias

Respuesta

2

La comparación de propiedad por propiedad debe repetirse en cada prueba, por lo que es una buena duplicación de código antiguo, a test smell described in XUnitPatterns. Mejor tener un adecuado equals().

Por supuesto, puede agregar un método de utilidad personEquals() o incluso anular Person.equals() en tiempo de ejecución. Para la clase burlada, es probable que tengas que hacerlo. Personalmente me apego al código más corto que es solo uno assertEquals() cuando sea posible.

2

Es curioso, yo y un colega tuvieron una discusión similar en la actualidad. Nuestra conclusión fue que

Una ventaja de la comparación atributo por atributo más laboriosa es que informa una diferencia específica en lugar de simplemente un "no, no son iguales", y esto puede ser conveniente.

Además, no teníamos control sobre ciertas clases, y algunas de ellas carecían de un método igual.

Tenemos la intención de investigar si es posible utilizar la reflexión para implementar un comparador, eliminando así parte del tedio.

+0

Véase también mi respuesta: La biblioteca commons-beans hace que sea sencillo utilizar el acceso basado en la reflexión, que se puede utilizar para crear métodos de afirmación de múltiples propiedades. –

1

Si equals está definido correctamente, tiene razón. El problema es que es posible que tengas que probar primero la unidad si iguales se define correctamente (lo que significa que se comporta de la manera que esperas).

Esto podría ser un poco más difícil si crea una maqueta para la clase Person. En ese caso, no le importa si iguales funciona correctamente, ya que solo desea verificar si algunos atributos se están configurando/accediendo correctamente. Es por eso que prefiero verificar valores primitivos si es posible y necesario. Encuentro que hace que las pruebas también sean más descriptivas (aunque pueden volverse bastante prolijas).

0

Como escribió, si los datos de prueba tienen un método de igual a igual, puede usarlo. "Correcto" significa que prueba los atributos que desea probar.

A menudo trabajo con entidades de base de datos que solo comparan su atributo de ID. Con estos objetos, necesito probar cada atributo por separado para ver si son iguales. Escribí un pequeño ayudante que me permite escribir una sola aserción de muchas propiedades, como esto:

assertEqualProperties(person, model['person'], "firstName", "lastName", "middleName"); 

Este método de ayuda utiliza la reflexión para acceder a los atributos (no directamente, invoco la biblioteca Commons en grano). En Groovy, seguramente hay una sintaxis que no necesita reflexión explícita. El método informa el primer atributo no igual como una falla de prueba.

0

En Grails cada objeto es serializable, por lo que se podría comparar los dos usando sus serializaciones XML:

public void compareXML(Object a, Object b) 
    ByteArrayOutputStream aBaos = new ByteArrayOutputStream(); 
    XMLEncoder aEncoder = new XMLEncoder(aBaos); 
    aEncoder.writeObject(a); 
    aEncoder.close(); 
    String xmlA = baos.toString(); 

    ByteArrayOutputStream bBaos = new ByteArrayOutputStream(); 
    XMLEncoder bEncoder = new XMLEncoder(bBaos); 
    bEncoder.writeObject(b); 
    bEncoder.close(); 
    String xmlB = bBaos.toString(); 

    assertEquals(xmlA, xmlB); 
} 

Si está trabajando en Eclipse, que obtendrá una gran comparación textual de las dos cadenas XML mostrando todas las diferencias.

+0

Grails 'GUnit hace un mejor trabajo en la representación textual de las diferencias de los objetos fuera de la caja. –

1

En esta instancia particular, probar las propiedades individuales es solo una forma de identificar una instancia específica de un objeto y nublar el significado de la prueba. Lo que importa específicamente sobre y debe afirmarse es que model['person'] es el mismo objeto exacto como lo que en un inicio se presento como person:

assertSame(person, model['person']) 

O con Hamcrest, lo que permite que tanto las afirmaciones más expresivos generales:

assertThat(model['person'], sameInstance(person)) 
+0

De hecho, si se espera que el objeto bajo prueba arroje la misma instancia que se colocó, se debe probar exactamente eso. –

0

Yo uso assertSame(). La comparación de campo por campo es mucho más trabajo de lo necesario: se burló de los datos, por lo que solo afirme que los valores falsificados se devuelven correctamente.

2

he encontrado que haciendo la propiedad por propiedad es un poco más fiable y le da un control de grano más fino poco sobre cómo se compara algo, la desventaja es que es un poco más de trabajo para establecer y mantener