Pregunta

Recientemente comencé a usar las herramientas de cobertura de códigos (especialmente Emma y EclEmma), y me gusta mucho la visión que me brinda sobre la integridad de mis pruebas de unidad, y la capacidad de ver qué áreas del código de mi unidad Las pruebas no están golpeando en absoluto. Actualmente trabajo en una organización que no hace muchas pruebas de unidad, y planeo realmente presionar a todos para que realicen pruebas de unidad y cobertura de código y TDD y, con suerte, convierta la organización.

Un problema del que no estoy seguro de este tema es exactamente hasta dónde debo llevar 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();
    }
}

Escribí algunas pruebas unitarias simples para asegurarme de que equals () funciona correctamente, que getValue () devuelve lo que esperaba, etc. Pero gracias a la naturaleza visual de EclEmma, ??el método hashcode () se muestra como rojo brillante para " no probado " ;.

¿Vale la pena siquiera molestarse en probar hashCode () , en este ejemplo, considerando lo sencilla que es la implementación? Siento que agregaría una prueba de unidad para este método simplemente para aumentar el% de cobertura del código y deshacerme del resaltado resaltado rojo que EclEmma agrega a estas líneas.

Tal vez estoy siendo neurótico y me gusta OCD, pero encuentro que usar algo como EclEmma que hace que sea tan fácil ver lo que no está probado, el complemento resalta el código fuente en rojo y el código cubierto en verde, realmente hace Quiero presionar para obtener la mayor cantidad de clases 100% verdes que pueda, incluso cuando no aporta mucho beneficio.

¿Fue útil?

Solución

Utilizo la cobertura de código para darme sugerencias 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 escriba un código que haga más de lo que se supone que debe hacer - digamos que podría detectar una excepción en un caso alternativo Que la prueba no haga ejercicio. Cuando uso el analizador de cobertura, puedo ver que introduje un código que no tiene una prueba asociada. Me ayuda saber cuándo no he escrito suficientes pruebas.

Por otro lado, el análisis de cobertura puede llevar 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 lo que debería hacer el código y escribir pruebas para asegurarse de que lo haga. Preferiblemente escribiendo 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 para el código hash 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 entusiasta acerca de escribir pruebas para accesores simples, por ejemplo. También es posible que no pruebe 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.

Otros consejos

Creo que vale la pena usar una biblioteca donde puedes elegir ignorar ciertos tipos de declaraciones. Por ejemplo, si tiene muchas:

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 (posiblemente) válido para desactivar los cálculos de cobertura para captadores y definidores triviales (aquellos que simplemente establecen o devuelven una variable miembro sin otras comprobaciones o efectos secundarios). Sin embargo, creo que si has anulado los iguales y el hashcode, estos deberían ser probados. Agregó una funcionalidad no trivial, y debería ser probada.

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

  • No probar esa funcionalidad está bien. No debería tener que ejecutar todo su conjunto de pruebas 5 veces, con la biblioteca de registro configurada para cada nivel de registro, solo para asegurarse de que todas sus declaraciones se encuentren afectadas.
  • Si hiciera lo anterior, desviaría su cobertura de otra manera. Si el 90% de sus sucursales son if (log.isDebugEnabled ()) , y las prueba a todas pero no a otras sucursales, parecerá que tiene una cobertura de sucursales del 90% (buena), cuando en realidad , tienes 0% de cobertura no trivial (¡mala!).

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

Considere el siguiente código:

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

Si ejecutó una prueba que pasó en un valor de 1.0, entonces obtendría un 100% de cobertura de código (sucursal y declaración) con todos los pases. El código obviamente tiene un defecto.

Medir la cobertura de las pruebas es más difícil y viene de convertirse en un mejor desarrollador y probador.

Con respecto a hashCode específicamente, un truista diría que debes realizar una prueba unitaria por separado para ese método. Personalmente, me aseguraría de que se incluya en al menos una prueba de integración de la unidad y no probaría cada accesor / modificador directamente. El retorno de su inversión es a menudo demasiado bajo para justificar el esfuerzo. Por supuesto, esto supone que tiene una prueba unitaria que garantiza que está generando el código hash correcto.

Alcanzar el 100% de cobertura de código con pruebas significativas puede no valer la pena y, como se mencionó anteriormente, el 100% de cobertura de código no significa necesariamente que todas las condiciones posibles en la aplicación hayan sido probado.

En cuanto a probar es igual a , hashCode y algunas otras interfaces basadas en contrato , como Comparable y Serializable , sí incluyo esas pruebas. Es importante que el contrato equals / hashCode se implemente correctamente, del mismo modo que con equals / Comparable .

Consulte JUnit-Addons , especialmente

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

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

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

Un compañero programador atrapado como yo en el antiguo Java1.4;)

Como se dice en mi anterior respuesta , el código cubierto no es un código probado. Y la conclusión fue: ¡desde cierto punto, la única forma de mejorar la cobertura del código es ... eliminar el código!

Ahora, con respecto al código hash, es interesante tenerlo cubierto en un diseño de prueba unitaria para verificar que se respeta el mecanismo ordenado esperado (y no para cubrir una función más)

Como he dicho en otra parte, la baja cobertura de código es un problema, pero la alta cobertura de código no significa que estés escribiendo oro puro.

Si no estaba preocupado por la cobertura de código, sugeriría que 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 quizás quiera probar eso.

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

En este caso particular, diría que, dado que está probando el método de iguales, también puede probar que los objetos iguales tienen códigos hash iguales: simplemente agregue una prueba adicional a todos los casos en los que se espera que devals sea verdadero .

Eso le dará cobertura al código, y en la negociación le dará cierta confianza de que el código hash cumple su contrato :-)

Solo tiene un valor marginal, dado que obviamente puedes confiar en el método hashCode de String y no esperas cambiar esta clase. Pero si sospechas lo suficiente de tu método de igual a igual para probarlo, entonces debes ser lo suficientemente sospechoso para probar que este y el hashCode permanecen consistentes. Y siempre debe sospechar de las suposiciones de que en el futuro no querrá meterse con lo que ha hecho antes. Por ejemplo, si alguien aparece y decide "optimizar" agregando una comprobación de igualdad de punteros, entonces también puede tener un conjunto completo de pruebas para que ejecuten su código modificado. De lo contrario, perderán el tiempo por la misma preocupación que usted: ¿está bien si no tengo cobertura de código?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top