¿Se supone que debemos escribir pruebas para nuestros captadores y establecedores o es excesivo?
unit-testing
Hector421
fuente
fuente
Respuestas:
Yo diría que no.
@Will dijo que deberías apuntar a una cobertura de código del 100%, pero en mi opinión es una distracción peligrosa. Puede escribir pruebas unitarias que tengan una cobertura del 100% y, sin embargo, no probar absolutamente nada.
Las pruebas unitarias están ahí para probar el comportamiento de su código, de manera expresiva y significativa, y los captadores / establecedores son solo un medio para un fin. Si las pruebas usan getters / setters para lograr su objetivo de probar la funcionalidad "real", entonces eso es lo suficientemente bueno.
Si, por otro lado, sus captadores y establecedores hacen más que simplemente obtener y configurar (es decir, son métodos propiamente complejos), entonces sí, deberían ser probados. Pero no escriba un caso de prueba de unidad solo para probar un captador o colocadores, eso es una pérdida de tiempo.
fuente
Roy Osherove en su famoso libro 'The Art Of Unit Testing' dice:
fuente
Un rotundo SÍ con TDD
Nota : Esta respuesta sigue recibiendo votos positivos, aunque potencialmente es un mal consejo. Para entender por qué, eche un vistazo a su hermana pequeña a continuación.
Muy controvertido, pero diría que a cualquiera que responda 'no' a esta pregunta le falta un concepto fundamental de TDD.
Para mí, la respuesta es un rotundo sí si sigues TDD. Si no lo eres, entonces no es una respuesta plausible.
El DDD en TDD
TDD es a menudo citado por tener los principales beneficios.
Separar la responsabilidad de la implementación
Como programadores, es terriblemente tentador pensar en los atributos como algo significativo y en captar y establecer como una especie de sobrecarga.
Pero los atributos son un detalle de implementación, mientras que los establecedores y captadores son la interfaz contractual que realmente hace que los programas funcionen.
Es mucho más importante deletrear que un objeto debe:
y
entonces cómo se almacena realmente este estado (para el cual un atributo es la forma más común, pero no la única).
Una prueba como
Es importante para la parte de documentación de TDD.
El hecho de que la implementación final es trivial (atributo) y no conlleva ningún beneficio de defensa debe ser desconocido para usted cuando escriba la prueba.
La falta de ingeniería de ida y vuelta ...
Uno de los problemas clave en el mundo del desarrollo del sistema es la falta de ingeniería de ida y vuelta 1 : el proceso de desarrollo de un sistema está fragmentado en subprocesos desarticulados cuyos artefactos (documentación, código) a menudo son inconsistentes.
1 Brodie, Michael L. "John Mylopoulos: cosiendo semillas del modelado conceptual". Modelado conceptual: fundamentos y aplicaciones. Springer Berlin Heidelberg, 2009. 1-9.
... y cómo lo resuelve TDD
Es la parte de documentación de TDD que asegura que las especificaciones del sistema y su código sean siempre consistentes.
Diseñe primero, implemente después
Dentro de TDD, primero escribimos la prueba de aceptación fallida, solo luego escribimos el código que les permitió pasar.
Dentro del BDD de nivel superior, primero escribimos escenarios y luego los hacemos pasar.
¿Por qué debería excluir setters y getter?
En teoría, es perfectamente posible dentro de TDD que una persona escriba la prueba y otra implemente el código que la hace pasar.
Entonces pregúntate a ti mismo:
Como getters y setters son una interfaz pública para una clase, la respuesta es obviamente sí , o no habrá forma de establecer o consultar el estado de un objeto. Sin embargo , la forma de hacerlo no es necesariamente probando cada método de forma aislada, consulte mi otra respuesta para obtener más información.
Obviamente, si escribe el código primero, la respuesta puede no ser tan clara.
fuente
tl; dr: Sí , deberías , y con OpenPojo es trivial.
Debería hacer alguna validación en sus captadores y definidores, por lo que debería probar eso. Por ejemplo,
setMom(Person p)
no debe permitir establecer a nadie más joven que ellos como su madre.Incluso si no está haciendo nada de eso ahora, lo más probable es que lo haga en el futuro, entonces esto será bueno para el análisis de regresión. Si desea permitir que las madres se establezcan
null
, debe hacerse una prueba para eso si alguien cambia eso más adelante, esto reforzará sus suposiciones.Un error común es
void setFoo( Object foo ){ foo = foo; }
dónde debería estarvoid setFoo( Object foo ){ this.foo = foo; }
. (En el primer caso, lofoo
que se está escribiendo es el parámetro, no elfoo
campo en el objeto ).Si está devolviendo una matriz o colección, debe probar si el getter realizará copias defensivas de los datos pasados al setter antes de regresar.
De lo contrario, si tiene los setters / getters más básicos, entonces la prueba unitaria de ellos agregará unos 10 minutos como máximo por objeto, entonces, ¿cuál es la pérdida? Si agrega comportamiento, ya tiene una prueba de esqueleto y obtiene esta prueba de regresión de forma gratuita. Si está utilizando Java, no tiene excusa ya que hay OpenPojo . Hay un conjunto de reglas existente que puede habilitar y luego escanear todo su proyecto con ellas para asegurarse de que se apliquen de manera consistente dentro de su código.
De sus ejemplos :
fuente
Sí, pero no siempre de forma aislada.
Permítame elaborar:
¿Qué es una prueba unitaria?
De trabajar eficazmente con el código heredado 1 :
Tenga en cuenta que con OOP, donde encuentra captadores y establecedores, la unidad es la clase , no necesariamente métodos individuales .
¿Qué es una buena prueba?
Todos los requisitos y pruebas siguen la forma de la lógica Hoare :
Dónde:
{P}
es la precondición ( dada )C
es la condición desencadenante ( cuando ){Q}
es la condición posterior ( entonces )Luego viene la máxima:
Esto significa que no debe probar cómo se
C
logra la condición posterior, debe verificar que{Q}
es el resultado deC
.Cuando se trata de OOP,
C
es una clase. Por lo tanto, no debe probar los efectos internos, solo los externos.¿Por qué no probar getters y setters de bean de forma aislada?
Los captadores y establecedores pueden involucrar algo de lógica, pero mientras esta lógica no tenga un efecto externo, lo que los convierte en accesores de frijoles 2 ) una prueba tendrá que mirar dentro del objeto y no solo violará la encapsulación sino también la prueba de implementación.
Por lo tanto, no debe probar los captadores y establecedores de beans de forma aislada. Esto es malo:
Aunque si
setVAT
arrojaría una excepción, una prueba correspondiente sería apropiada ya que ahora hay un efecto externo.¿Cómo deberías probar getters y setters?
Prácticamente no tiene sentido cambiar el estado interno de un objeto si dicho cambio no tiene efecto en el exterior, incluso si dicho efecto llega más tarde.
Por lo tanto, una prueba para setters y getters debería estar relacionada con el efecto externo de estos métodos, no con los internos.
Por ejemplo:
Puedes pensar para ti mismo:
Pero si el
setVAT()
mal funcionamiento de esa prueba fallara de todos modos1 Feathers, M., 2004. Trabajando efectivamente con código heredado. Prentice Hall Profesional.
2 Martin, RC, 2009. Código limpio: un manual de artesanía ágil de software. Educación Pearson.
fuente
Si bien existen razones justificadas para las Propiedades, existe una creencia común de Diseño Orientado a Objetos de que exponer el estado miembro a través de Propiedades es un mal diseño. El artículo de Robert Martin sobre el Principio Abierto Cerrado amplía esto al afirmar que las Propiedades fomentan el acoplamiento y, por lo tanto, limitan la capacidad de cerrar una clase de la modificación; si modifica la propiedad, todos los consumidores de la clase también deberán cambiar. Él califica que exponer las variables miembro no es necesariamente un mal diseño, sino que podría ser un mal estilo. Sin embargo, si las propiedades son de solo lectura, hay menos posibilidades de abuso y efectos secundarios.
El mejor enfoque que puedo proporcionar para las pruebas unitarias (y esto puede parecer extraño) es hacer que todas las propiedades sean protegidas o internas. Esto evitará el acoplamiento y desalienta la escritura de pruebas tontas para captadores y establecedores.
Existen razones obvias en las que se deben usar las propiedades de lectura / escritura, como las propiedades de ViewModel que están vinculadas a campos de entrada, etc.
Más prácticamente, las pruebas unitarias deberían conducir la funcionalidad a través de métodos públicos. Si el código que está probando utiliza esas propiedades, obtendrá cobertura de código de forma gratuita. Si resulta que estas propiedades nunca se destacan por la cobertura de código, existe una gran posibilidad de que:
Si escribe pruebas para captadores y establecedores, obtiene una falsa sensación de cobertura y no podrá determinar si las propiedades son realmente utilizadas por el comportamiento funcional.
fuente
Si la complejidad ciclomática del captador y / o definidor es 1 (que generalmente son), entonces la respuesta es no, no debería.
Por lo tanto, a menos que tenga un SLA que requiera una cobertura de código del 100%, no se moleste y concéntrese en probar el aspecto importante de su software.
PD Recuerde diferenciar getters y setters, incluso en lenguajes como C # donde las propiedades pueden parecer lo mismo. La complejidad del setter puede ser mayor que la del getter y, por lo tanto, validar una prueba unitaria.
fuente
Una toma humorística pero sabia: El camino de Testivus
"Escribe el examen que puedas hoy"
Las pruebas de getters / setters pueden ser excesivas si eres un probador experimentado y este es un proyecto pequeño. Sin embargo, si recién está comenzando a aprender a hacer pruebas unitarias o estos captadores / establecedores pueden contener lógica (como el
setMom()
ejemplo de @ ArtB ), sería una buena idea escribir pruebas.fuente
Este ha sido un tema reciente entre mi equipo y yo. Disparamos por una cobertura de código del 80%. Mi equipo argumenta que los getters y setters se implementan automáticamente, y el compilador está generando un código básico detrás de escena. En este caso, dado que el código generado no es intrusivo, realmente no tiene sentido probar el código que el compilador crea para usted. También tuvimos esta discusión sobre los métodos asíncronos y en ese caso el compilador genera un montón de código detrás de escena. Este es un caso diferente y algo que SI probamos. Respuesta larga corta, tráigala con su equipo y decida por sí mismo si vale la pena probarlo.
Además, si está utilizando el informe de cobertura de código como nosotros, una cosa que puede hacer es agregar el atributo [ExcludeFromCodeCoverage]. Nuestra solución ha sido usar esto para modelos que solo tienen propiedades que usan getters y setters, o en la propiedad misma. De esa manera, no afectará el% de cobertura total del código cuando se ejecute el informe de cobertura del código, suponiendo que eso es lo que está utilizando para calcular los porcentajes de cobertura del código. ¡Feliz prueba!
fuente
En mi opinión, la cobertura del código es una buena manera de ver si perdió alguna funcionalidad que debería cubrir.
Cuando inspecciona la cobertura manualmente por su colorido, entonces se puede argumentar que los captadores y establecedores simples no necesitan ser probados (aunque siempre lo hago).
Cuando solo verifica el porcentaje de cobertura del código en su proyecto, entonces un porcentaje de cobertura de prueba como 80% no tiene sentido. Puede probar todas las partes no lógicas y olvidar algunas partes cruciales. En este caso, solo el 100% significa que ha probado todo su código vital (y también todo el código no lógico). Tan pronto como sea del 99,9%, sabes que has olvidado algo.
Por cierto: la cobertura del código es la verificación final para ver si ha probado completamente (unidad) una clase. Pero la cobertura del 100% del código no significa necesariamente que haya probado toda la funcionalidad de la clase. Por lo tanto, las pruebas unitarias siempre deben implementarse siguiendo la lógica de la clase. Al final, ejecutas la cobertura para ver si olvidaste algo. Cuando lo hiciste bien, llegaste al 100% la primera vez.
Una cosa más: mientras trabajaba recientemente en un gran banco en los Países Bajos, noté que Sonar indicaba una cobertura de código del 100%. Sin embargo, sabía que faltaba algo. Al inspeccionar los porcentajes de cobertura de código por archivo, indicó un archivo con un porcentaje más bajo. El porcentaje base del código completo era tan grande que el único archivo no hizo que el porcentaje se mostrara como 99.9%. Por lo tanto, es posible que desee vigilar esto ...
fuente
Hice un pequeño análisis de la cobertura lograda en el propio código JUnit .
Una categoría de código descubierto es "demasiado simple para probar" . Esto incluye getters y setters simples, que los desarrolladores de JUnit no prueban.
Por otro lado, JUnit no tiene ningún método (no obsoleto) de más de 3 líneas que no esté cubierto por ninguna prueba.
fuente
Yo diría: SÍ Los errores en los métodos getter / setter pueden colarse silenciosamente y causar algunos errores feos.
He escrito una lib para facilitar esta y algunas otras pruebas. Lo único que tienes que escribir en tus pruebas JUnit es esto:
-> https://github.com/Mixermachine/base-test
fuente
Sí, especialmente si el elemento a obtener es un objeto de una clase subclase de una clase abstracta. Su IDE puede o no alertarlo de que cierta propiedad no se ha inicializado.
Y luego, una prueba aparentemente no relacionada se bloquea con a
NullPointerException
y le lleva un tiempo darse cuenta de que una propiedad obtenible no está allí para obtenerla en primer lugar.Aunque eso no sería tan malo como descubrir el problema en la producción.
Puede ser una buena idea asegurarse de que todas sus clases abstractas tengan constructores. Si no, la prueba de un captador podría alertarlo sobre un problema allí.
En cuanto a los captadores y establecedores de primitivas, la pregunta podría ser: ¿Estoy probando mi programa o estoy probando JVM o CLR? En términos generales, la JVM no necesita ser probada.
fuente