2012-04-13 35 views
12

En Java/Junit, necesito probar null con algún objeto. Hay una variedad de formas en que puedo probar una condición, pero he estado usando assertTrue para la mayoría de mis pruebas. Cuando compruebo nulls en assertTrue, EclEmma afirma que solo está probando una rama.Falta de ramas al utilizar assertTrue en lugar de assertNull

Cuando resuelvo el enunciado en una variable de forma manual (como establecer el resultado en un booleano y pasarlo a assertTrue) la cobertura del código se considera completa en la afirmación pero no en la línea de inicialización de la variable.

¿Por qué sucede esto? ¿Esto está relacionado con el código de bytes adicionales que Java aparentemente agrega como se menciona en http://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions? Cualquier solución (además de usar otras declaraciones de afirmación).

assertTrue:

assertTrue(myObject == null); //1 of 2 branches 

assertTrue:

boolean test = (myObject == null); //1 of 2 branches missing 
assertTrue(test); // complete 

assertNull:

assertNull(myObject) //complete; 
+1

Qué le pasa a valer cero mediante el uso de assertNull? Por lo general, es mejor usar el tipo de afirmación apropiado para lo que se afirma. Será mejor que veas lo que está mal cuando la prueba falla sin excavar demasiado en el código de prueba. – nansen

+0

@nansen Esto es cierto y no tengo ningún problema para usar assertNull si es un requisito, sin embargo, IMO, todos los "tipos" afirmar son solo otra forma de assertTrue. Puede haber beneficios adicionales al uso de diferentes tipos de afirmaciones, como la información/legibilidad de errores añadida, pero eso no es realmente un problema aquí. –

+0

@nansen Eso no quiere decir que me niegue a usar assertNull y probablemente lo use, solo encontré este problema en particular, ya que básicamente estoy probando lo mismo pero Emma da resultados completamente diferentes. –

Respuesta

16

Para la mayoría de Boole expressi ons, el compilador de Java genera ramas adicionales en el código de bytes. JaCoCo produce "cobertura de sucursal" basada en el código de bytes generado, no basado en el código original de Java, y por lo tanto muestra información adicional de cobertura de sucursal para casi cualquier expresión booleana que utilice.

En su código, la expresión booleana que utiliza es myObject == null.

Para calcular este valor, el compilador de Java genera código presionando los dos argumentos en la pila y luego haciendo un salto condicional para insertar 1 (verdadero) o 0 (falso) en la pila. JaCoCo informa la cobertura de sucursal de este salto condicional.

Por lo tanto, el hecho de que utilice myObject == null desencadena el comportamiento que describe.

Como algunos otros ejemplos, intente esto:

boolean t = true; 
boolean f = false; 
boolean result1 = (t && f) || f; // 3 out of 6 missed. 
boolean result2 = !t;   // 1 out of 2 missed. 

Esto puede ser útil si la expresión booleana es, por ejemplo, devuelto por una función, que se utiliza como condición en una instrucción if-then-else en algún otro lugar. Aunque en su mayoría es una consecuencia de la forma en que funciona el compilador de Java, ayuda a evaluar condición cobertura (en lugar de la simple rama cobertura) del código original de Java.

Esta función no está muy bien documentada, pero aquí hay algunos consejos:

así es, en efecto, relacionado con el código byte adicional se genera, pero no a los ejemplos específicos de construcciones de bytes compilador sintéticos para los que se destinan las opciones de filtrado.

NOTA: La edición MAYOR desde la respuesta inicial fue demasiado suposición. Gracias a @ ira-baxter por buena discusión crítica &.

1

El hecho de que Emma trate una expresión condicional como "algo con una sucursal" para el recuento de coberturas de (sucursal) en mi humilde opinión parece simplemente quebrado. No es una rama condicional.

Podemos discutir más sobre el Assert; si se definió como "arroja una excepción sobre la falla afirmativa", entonces realmente tiene una rama conditonal; si está definido [como creo que lo hago, no soy un experto en Java] como "terminar mi programa al afirmar el fallo", entonces no es realmente una rama. También son oscuras las llamadas a métodos; estos son ramas condicionales en el sentido de que si el método llamado arroja una excepción, el flujo de control no continúa al "resto de la instrucción".

Nuestra herramienta Java Test Coverage obtiene el análisis de cobertura (ramificación) en tales condicionales "a la derecha".

+0

No hay nada de especial en los métodos assertTrue/assertNull de la API JUnit. Simplemente lanzan un java.lang.AssertionError si la condición no se cumple. Esto no está directamente relacionado con la palabra clave 'assert' de Java. – avandeursen

+0

Acepto que llamar a esta característica de Emma/JaCoCo * cobertura de sucursal * es (muy) confuso. Sin embargo, la información de cobertura (separada) que me indica cualquier expresión (sub) booleana, si se evaluó como verdadera y falsa es una característica útil. – avandeursen

+0

@avandeursen: determinar si cada * condición * en un programa se ha ejercido como "verdadero" o "falso" no es una cobertura de sucursal; es "cobertura de condición". Ciertamente, nuestra herramienta no cubre la condición; basado en el entendimiento del pasado, no creo que Emma condicione la cobertura, pero podría sorprenderme. –

0

Para obtener cobertura de código 100% en los métodos booleanos, haga lo siguiente

Class RecordService{ 


    public boolean doesRecordExist(String id){ 

    return id!=null; 

    } 


    } 

    //Method inside your mock 
    @Test 
    public boolean testDoesRecordExist(){ 
    RecordService recordService = mock(RecordService.class); 
    when(recordService.doesRecordExists()).thenReturn(
        anyString()).thenReturn(null); 

    } 
Cuestiones relacionadas