2011-02-17 9 views
9

Tengo un DTO que estoy rellenando desde el objeto de solicitud, y el objeto de solicitud tiene muchos campos. Quiero escribir una prueba para verificar si el método populateDTO() está poniendo valores en los lugares correctos o no. Si sigo la regla de una afirmación por prueba, tendría que escribir una gran cantidad de pruebas para probar cada campo. El otro enfoque sería escribir múltiples aseveraciones en una sola prueba. ¿Realmente se recomienda seguir una regla de afirmación por prueba o podemos relajarnos en estos casos? ¿Cómo abordo este problema?¿Cómo evitar las afirmaciones múltiples en una prueba JUnit?

Respuesta

0

¿Esa regla se extiende a estar en un bucle? Considere esto

Collection expectedValues = // populate expected values 
populateDTO(); 
for(DTO dto : myDtoContainer) 
    assert_equal(dto, expectedValues.get(someIndexRelatedToDto)) 

ahora no estoy tan grande en la sintaxis exacta, pero esto es sólo la idea de que estoy viendo.

EDIT: Después de los comentarios ...

La respuesta es ... No!

La razón por la cual existe este principio es para que pueda identificar qué partes del objeto fallan. Si los tiene en un método, se encontrará con una sola afirmación, luego con la siguiente y luego con la siguiente, y no las verá todas.

para que pueda tener en una de dos maneras:

  1. Un método, menos código repetitivo.
  2. muchos métodos, mejores informes sobre la marcha de prueba

Todo depende de usted, ambos tienen altibajos. 3. Elemento de la lista

+0

El DTO es POJO ... y la solicitud también es un POJO. Entonces, el assertes se parecerá más a assertEqual ("abc", dto.getName()); etc. – Ravi

+0

Así que quieres evitar tener 'assert (dto.equals (mockObject)', ¿es eso lo que estás diciendo?¿Desea afirmar cada elemento individual sin violar el principio de 1 por? – corsiKa

+0

Sí, quiero afirmar cada elemento individual, sin violar el principio de 1 por. Solo que lo sabe, la solicitud es un objeto generado por JAXB. – Ravi

1

Puede tener un parameterized test donde el primer parámetro es el nombre de la propiedad y el segundo el valor esperado.

-1

O puede hacer alguna solución.

import junit.framework.Assert; 
import org.junit.After; 
import org.junit.AfterClass; 
import org.junit.Before; 
import org.junit.BeforeClass; 
import org.junit.Test; 

public class NewEmptyJUnitTest { 

    public NewEmptyJUnitTest() { 
    } 

    @BeforeClass 
    public static void setUpClass() throws Exception { 
    } 

    @AfterClass 
    public static void tearDownClass() throws Exception { 
    } 

    @Before 
    public void setUp() { 
    } 

    @After 
    public void tearDown() { 
    } 


    @Test 
    public void checkMultipleValues() { 
     String errMessages = new String(); 

     try{ 
      this.checkProperty1("someActualResult", "someExpectedResult"); 
     } catch (Exception e){ 
      errMessages += e.getMessage(); 
     } 

     try{ 
      this.checkProperty2("someActualResult", "someExpectedResult"); 
     } catch (Exception e){ 
      errMessages += e.getMessage(); 
     } 

     try{ 
      this.checkProperty3("someActualResult", "someExpectedResult"); 
     } catch (Exception e){ 
      errMessages += e.getMessage(); 
     } 

     Assert.assertTrue(errMessages, errMessages.isEmpty()); 


    } 



    private boolean checkProperty1(String propertyValue, String expectedvalue) throws Exception{ 
     if(propertyValue == expectedvalue){ 
      return true; 
     }else { 
      throw new Exception("Property1 has value: " + propertyValue + ", expected: " + expectedvalue); 
     } 
    } 

     private boolean checkProperty2(String propertyValue, String expectedvalue) throws Exception{ 
     if(propertyValue == expectedvalue){ 
      return true; 
     }else { 
      throw new Exception("Property2 has value: " + propertyValue + ", expected: " + expectedvalue); 
     } 
    } 

     private boolean checkProperty3(String propertyValue, String expectedvalue) throws Exception{ 
     if(propertyValue == expectedvalue){ 
      return true; 
     }else { 
      throw new Exception("Property3 has value: " + propertyValue + ", expected: " + expectedvalue); 
     } 
    } 
} 

Tal vez no sea el mejor enfoque y si se usa en exceso que puede confundir ... pero es una posibilidad.

+0

Diría que cualquier uso es uso excesivo. ¿Todo esto repetitivo simplemente para evitar la 'afirmación individual por prueba'? – merryprankster

+0

@merryprankster Bueno, sí, si no tiene una herramienta que lo haga por usted, entonces debe escribir esto por su cuenta. Una vez que encuentre usando esto más y más, hará esta utilidad general. En algún momento quizás agregue esto a su marco de pruebas: https://github.com/KentBeck/junit/blob/r4.8.2/src/main/java/org/junit/rules/ErrorCollector.java – yoosiba

7

Guárdelos por separado. Se supone que una prueba de unidad le dirá qué unidad falló. Mantenerlos separados también le permite aislar el problema rápidamente sin requerir que pase por un largo ciclo de depuración.

+0

Enlaces rotos - por favor enmendar y hágamelo saber –

+0

Todavía enlaces rotos. Esta es la razón por la cual es mejor alinear su respuesta y usar enlaces para soporte que proporcionar enlaces como la parte principal de su respuesta. – Jay

+0

Se han corregido los enlaces rotos. Disculpe las molestias. – Nilesh

0

[advertencia: Estoy muy "unfluent" en Java/JUnit, así que ten cuidado con los errores en los datos a continuación]

Hay un par de maneras de hacer esto:

1) múltiples afirmaciones en la misma prueba. Esto debería estar bien si solo está probando la generación de DTO una vez. Podría comenzar aquí y pasar a otra solución cuando esto empiece a doler.

2) Escriba una aserción de ayudante, p. Ej. assertDtoFieldsEqual, pasando el DTO esperado y real. Dentro de la afirmación de ayudante afirmas cada campo por separado. Esto al menos le da la ilusión de solo una afirmación por prueba y aclarará las cosas si prueba la generación de DTO para múltiples escenarios.

3) Implementar iguales para el objeto que verifica cada propiedad e implementar toString para que al menos pueda inspeccionar el resultado de la aserción manualmente para descubrir qué parte es incorrecta.

4) Para cada escenario donde se genera el DTO, cree un dispositivo de prueba separado que genere el DTO e inicialice las propiedades esperadas en el método setUp. Cree una prueba separada para probar cada una de las propiedades. Esto también da como resultado muchas pruebas, pero al menos serán de una sola línea. Ejemplo de pseudo-código:

public class WithDtoGeneratedFromXxx : TestFixture 
{ 
    DTO dto = null; 

    public void setUp() 
    { 
    dto = GenerateDtoFromXxx(); 
    expectedProp1 = ""; 
    ... 
    } 

    void testProp1IsGeneratedCorrectly() 
    { 
    assertEqual(expectedProp1, dto.prop1); 
    } 
    ... 
} 

Si necesita probar la generación DTO en diferentes escenarios y elegir este último método que pronto podría llegar a ser tedioso para escribir todas esas pruebas. Si este es el caso, podría implementar un accesorio base abstracto que omita los detalles sobre cómo crear el DTO y configurar las propiedades esperadas para las clases derivadas. Pseudocódigo:

abstract class AbstractDtoTest : TestFixture 
{ 
    DTO dto; 
    SomeType expectedProp1; 

    abstract DTO createDto(); 
    abstract SomeType getExpectedProp1(); 

    void setUp() 
    { 
    dto = createDto(); 
    ... 
    } 

    void testProp1IsGeneratedCorrectly() 
    { 
    assertEqual(getExpectedProp1(), dto.prop1); 
    } 
    ... 
} 


class WithDtoGeneratedFromXxx : AbstractDtoTest 
{ 
    DTO createDto() { return GenerateDtoFromXxx(); } 
    abstract SomeType getExpectedProp1() { return new SomeType(); } 
    ... 
} 
+0

Si desea que una función confirme todos los campos de propiedades, le recomendamos que consulte la clase hamcrest [SamePropertyValuesAs] (http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/beans/SamePropertyValuesAs.html) . Puede usar eso en Assert.assertThat (returnedDto, samePropertyValuesAs (expectedDto)). (Esto todavía le da solo 1 error por prueba, incluso cuando más campos son incorrectos). –

4

¿Realmente se recomienda tener only one assert per unit test? Sí lo es, hay personas que hacen esa recomendación. ¿Están en lo cierto? No lo creo. Me resulta difícil creer que esas personas hayan trabajado en código real durante mucho tiempo.

Por lo tanto, imagina que tienes un método de mutador que quieres probar en una unidad. El mutador tiene algún tipo de efecto, o efectos, que desea verificar. Típicamente, el efecto esperado de un mutador es reducido, debido a que muchos efectos sugieren un diseño excesivamente complicado para el mutador. Con una afirmación por efecto y un caso de prueba por afirmación, no necesitará muchos casos de prueba por mutador, por lo que la recomendación no parece tan mala.

Pero la falla en este razonamiento es que esas pruebas solo buscan los efectos esperados del mutador. Pero si el mutador tiene un error, puede tener efectos secundarios inesperados. Las pruebas están haciendo la absurda suposición de que el código no tiene una clase completa de errores, y que ninguna refacturación futura introducirá dichos errores. Cuando el método fue escrito originalmente, podría ser obvio para el autor que ciertos efectos secundarios eran imposibles, pero la refacturación y la adición de nuevas funcionalidades podrían hacer posibles tales efectos secundarios.

La única manera segura de probar el código de larga vida es comprobar que los mutadores no tengan efectos secundarios inesperados. Pero, ¿cómo puedes probar eso? La mayoría de las clases tienen invariantes: cosas que ningún mutador puede cambiar. El método size de un contenedor nunca devolverá un valor negativo, por ejemplo. Cada invariante es, en efecto, una condición de publicación para cada mutador (y también el constructor). Cada mutador también tiene típicamente un conjunto de invariantes que describen qué tipo si los cambios mueren no hacen. Un método sort no cambia la longitud del contenedor, por ejemplo. Las invariantes de clase y de mutador son, en efecto, condiciones de postulación para cualquier llamada de mutador. Agregar afirmaciones para ellos es la única manera de verificar los efectos secundarios inesperados.

Entonces, solo agregue más casos de prueba? En la práctica, el número de invariantes multiplicado por el número de mutadores para evaluar es grande, por lo que una afirmación por prueba lleva a muchos casos de prueba. Y la información sobre usted invariantes está dispersa en muchos casos de prueba. Un cambio de diseño para modificar un invariante requerirá la modificación de muchos casos de prueba. Se vuelve poco práctico. Es mejor tener casos de prueba parametrizados para un mutador, que verifique varias invariantes para el mutador, usando varias afirmaciones.

Cuestiones relacionadas