2008-10-31 28 views
8

Recientemente comencé a usar herramientas de cobertura de código (especialmente Emma y EclEmma), y realmente me gusta la vista que me da sobre la integridad de mis pruebas de unidad y la capacidad de ver qué áreas del código mi unidad prueba no están pegando en absoluto. Actualmente trabajo en una organización que no realiza muchas pruebas unitarias, y tengo la intención de presionar a todos para que realicen las pruebas unitarias y la cobertura de códigos y TDD y, con suerte, convierta la organización.¿Qué distancia toma la cobertura del código?

Un problema que no estoy seguro con este tema es exactamente qué tan lejos debo tomar la cobertura de mi código. Por ejemplo, si tengo una clase como esta:

//this class is meant as a pseudo-enum - I'm stuck on Java 1.4 for time being 
public final class BillingUnit { 

    public final static BillingUnit MONTH = new BillingUnit("month"); 
    public final static BillingUnit YEAR = new BillingUnit("year"); 

    private String value; 

    private BillingUnit(String value) { 
     this.value = value; 
    } 

    public String getValue() { 
     return this.value; 
    } 

    public boolean equals(Object obj) { 
     return value.equals(((BillingUnit) obj).getValue()); 

    } 

    public int hashCode() { 
     return value.hashCode(); 
    } 
} 

me escribió algunas pruebas unitarias simples para asegurarse de que funciona correctamente equals(), que vuelve getValue() lo que esperaba, etc, pero gracias a la naturaleza visual de EclEmma , el método hashcode() aparece como rojo brillante para "no probado".

¿Vale la pena incluso molestarse en probar hashCode(), en este ejemplo, considerando cuán simple es la implementación? Siento que estaría agregando una prueba unitaria para este método simplemente para aumentar la cobertura del código% arriba, y deshacerme de la luz roja deslumbrante que EclEmma agrega a estas líneas.

Tal vez estoy siendo neurótico y OCD, pero encuentro que usar algo como EclEmma hace que sea tan fácil ver lo que no se ha probado: el complemento resalta el código fuente en rojo y el código cubierto en verde, realmente me da ganas de presionar para obtener tantas clases 100% ecológicas como pueda, incluso cuando no aporten mucho beneficio.

Respuesta

8

Uso la cobertura de código para darme pistas sobre lugares donde puedo tener un conjunto incompleto de pruebas. Por ejemplo, puedo escribir una prueba para alguna funcionalidad dada, luego desarrollar el código que satisfaga esa funcionalidad, pero al hacerlo, realmente escribir código que hace más de lo que se supone que debe - decir que podría atrapar una excepción en un caso alternativo que la prueba no se ejercita. Cuando uso el analizador de cobertura, puedo ver que he introducido un código que no tiene una prueba asociada. Me ayuda a saber cuándo no he escrito suficientes pruebas.

Por otro lado, el análisis de cobertura puede dar lugar a una seguridad falsa. Tener todo su código cubierto no significa que tenga suficientes pruebas. Debe pensar en las pruebas desde la perspectiva de qué debería hacer el código y escribir pruebas para asegurarse de que lo haga. Preferiblemente al escribir la prueba primero. El hecho de que su código esté completamente cubierto no significa que el código haga lo que se supone que debe hacer.

En su ejemplo, habría escrito la prueba de hashCode para definir qué hace la funcionalidad del método, antes de escribir el código. Por lo tanto, lo tendría cubierto. Eso no significa que siempre tenga una cobertura del 100%. No soy demasiado celoso acerca de escribir pruebas para accesadores simples, por ejemplo. También es posible que no pruebe los métodos de la clase principal donde heredo de un marco, ya que no siento la necesidad de probar el código de otras personas.

2

Puede que ahora no sea demasiado complicado, pero una simple comprobación para verificar que sigue funcionando como se espera puede ser muy útil más adelante si se modifica el método.

Dado que el cheque debería ser realmente fácil de escribir, ¿por qué no hacerlo? Ayuda a las estadísticas, y también ayuda a darle un cheque más tarde en caso de que se rompa.

Además, para TDD, desea una cobertura del 100%, porque entonces puede estar seguro (o muy cerca) de que no está rompiendo nada cuando refactorice.

6

Creo que vale la pena usar una biblioteca donde puede elegir ignorar ciertos tipos de declaraciones. Por ejemplo, si usted tiene un montón de:

if(logger.isDebugEnabled()) { 
    logger.debug("something"); 
} 

Es útil si puede desactivar los cálculos de cobertura para ese tipo de líneas. También puede ser (argumentablemente) válido desactivar los cálculos de cobertura para captadores y establecedores triviales (aquellos que simplemente establecen o devuelven una variable miembro sin otras verificaciones o efectos secundarios). Sin embargo, creo que si has reemplazado a equals y hashcode, debes probarlos. Agregaste una funcionalidad no trivial y debería probarse.

Para que quede claro, la razón que creo las situaciones anteriores deben ser excluidos de la cobertura es que:

  • No prueba que la funcionalidad está bien. No debería tener que ejecutar toda su serie de pruebas 5 veces, con la biblioteca de registro configurada para cada nivel de registro, solo para asegurarse de que todas sus declaraciones sean aciertas.
  • Si hizo lo anterior, sesgaría su cobertura en el otro sentido. Si el 90% de sus sucursales son if(log.isDebugEnabled()), y las prueba todas menos ninguna otra, parecerá que tiene 90% de cobertura de sucursales (buena), cuando en realidad tiene 0% de cobertura de sucursales no triviales (¡¡malo !!)
+0

Creo que este es un buen punto. Aunque para manejar esto, hice algo de mi objetivo emma y utilicé una configuración de log4j con el registrador de raíz establecido en DEPURAR, y los filtros del appender en el nivel DESACTIVADO (para que todas las sentencias log.debug() sean accionadas, pero no registradas en ninguna parte) . –

+0

Todavía se encontrará con problemas, porque si revisa el nivel de registro, siempre se evaluará como verdadero (o falso, dependiendo de la configuración), por lo que la cobertura de su sucursal será solo del 50%. –

+0

Pero no estoy haciendo ninguna rama, no hay más para si (log.isDebugEnabled()) - ¿verdad? –

0

Como he dicho en otros lugares, la baja cobertura de código es un problema, pero la alta cobertura de código no significa que está escribiendo oro puro.

Si no estaban preocupados por código de cobertura, a continuación, me gustaría sugerir que se necesitaría pruebas para equals() y getValue() - dependiendo de cómo y dónde se está utilizando hashCode() (lo siento, soy un desarrollador de C#) , entonces usted podría quiere probar eso.

Lo más importante es que sus pruebas le dan la seguridad de que ha escrito el código correcto y de que el código funciona como se esperaba.

1

Un compañero programador pegado como yo en edad Java1.4;)

Como se ha dicho en mi previous answer, código cubierto no está probado código. Y la conclusión fue: desde cierto punto, la única forma de mejorar la cobertura del código es ... ¡borrar el código!

Ahora, con respecto hashCode, es interesante lo han cubierto en un diseño de prueba de la unidad Para comprobar se respeta el mecanismo ordenado de esperar (y no para cubrir una función más)

4

Hay una diferente entre la cobertura de código y prueba de cobertura. Debe intentar asegurarse de que su código esté adecuadamente probado en lugar de tener una cobertura de código del 100%.

Considere el siguiente código:

public float reciprocal (float ex) 
{ 
    return (1.0/ex) ; 
} 

Si ejecutó una prueba que transcurrió en un valor de 1,0, entonces sería obtener el 100% de cobertura de código (sucursal y declaración) con todos los pases. El código obviamente tiene un defecto.

La cobertura de prueba de medición es más difícil y la que viene de convertirse en un mejor desarrollador y tester.

Con respecto a hashCode específicamente, un truist diría que debe tener una prueba de unidad separada para ese método.Personalmente me aseguraré de incluirlo en al menos una prueba de integración de unidades y no probaría cada acceso/modificador directamente. El rendimiento de su inversión a menudo es demasiado bajo para justificar el esfuerzo. Esto supone, por supuesto, que tiene una prueba de unidad que garantiza que está generando el código hash correcto.

+1

El código anterior solo tiene un defecto si recíproco() se puede pasar a cero. Si no, entonces el código está completo. Si puede, entonces debería haber escrito una prueba que pruebe ese escenario. – quamrana

3

Alcanzar la cobertura del código 100% con pruebas significativas puede no valer la pena escalar, y, como se mencionó anteriormente, 100% Code Coverage no significa necesariamente que todas las condiciones posibles en la aplicación han sido probadas.

En cuanto a las pruebas de equals, hashCode y algunos otros contratos basado interfaces, como Comparable y Serializable, yo incluyen aquellas pruebas. Es importante que el contrato equals/hashCode se implemente correctamente, del mismo modo con equals/Comparable.

Ver JUnit-Addons, especialmente

0

En este caso particular, yo diría que desde que está probando el método equals, que como se puede También pruebe que los objetos iguales tienen códigos hash iguales: simplemente agregue una prueba adicional a todos los casos donde se espera que los iguales retu r verdadero.

que le dará cobertura de código, y en la negociación que le dará cierta confianza en que hashCode satisface realmente su contrato :-)

Es sólo marginalmente vale la pena, ya que es obvio que se puede confiar en el método hashCode de los Hilos , y no esperas que alguna vez cambie esta clase. Pero si sospecha lo suficiente de su método de igual para probarlo, entonces debe sospechar lo suficiente como para probar que tanto él como HashCode permanecen consistentes. Y siempre debes desconfiar de las suposiciones de que en el futuro no querrás meter la pata con lo que has hecho antes. Por ejemplo, si alguien viene y decide 'optimizar' agregando un control de igualdad de puntero, entonces también puede tener un conjunto completo de pruebas para que ejecute su código modificado. De lo contrario, perderán el tiempo con la misma preocupación que usted: ¿está bien que no tenga cobertura de código?

Cuestiones relacionadas