Estamos tratando de diseñar nuestro sistema para que sea comprobable y en la mayoría de las partes desarrollado utilizando TDD. Actualmente estamos tratando de resolver el siguiente problema:
En varios lugares, es necesario que usemos métodos auxiliares estáticos como ImageIO y URLEncoder (ambos API Java estándar) y varias otras bibliotecas que consisten principalmente en métodos estáticos (como las bibliotecas Apache Commons). Pero es extremadamente difícil probar esos métodos que usan tales clases auxiliares estáticas.
Tengo varias ideas para resolver este problema:
- Use un marco simulado que pueda simular clases estáticas (como PowerMock). Esta puede ser la solución más simple, pero de alguna manera se siente como darse por vencido.
- Cree clases de contenedor instanciables alrededor de todas esas utilidades estáticas para que puedan inyectarse en las clases que las usan. Esto suena como una solución relativamente limpia, pero me temo que terminaremos creando una gran cantidad de esas clases de contenedor.
- Extraiga cada llamada a estas clases auxiliares estáticas en una función que se pueda anular y pruebe una subclase de la clase que realmente quiero probar.
Pero sigo pensando que esto solo tiene que ser un problema que muchas personas deben enfrentar al hacer TDD, por lo que ya debe haber soluciones para este problema.
¿Cuál es la mejor estrategia para mantener comprobables las clases que usan estos ayudantes estáticos?
fuente
Respuestas:
(Me temo que no hay fuentes "oficiales" aquí; no es que haya una especificación sobre cómo hacer una buena prueba. Solo mis opiniones, que espero sean útiles).
Cuando estos métodos estáticos representan dependencias genuinas , cree envoltorios. Entonces para cosas como:
... tiene sentido crear una interfaz.
Pero muchos de los métodos en Apache Commons probablemente no deberían ser burlados / falsificados. Por ejemplo, tome un método para unir una lista de cadenas, agregando una coma entre ellas. No tiene sentido burlarse de estos: simplemente deje que la llamada estática haga su trabajo normal. No quiere ni necesita reemplazar el comportamiento normal; no se trata de un recurso externo o algo con lo que es difícil trabajar, solo son datos. El resultado es predecible y nunca querrás que sea otra cosa que lo que te dará de todos modos.
Sospecho que habiendo eliminado todas las llamadas estáticas que realmente son métodos convenientes con resultados predecibles, "puros" (como base64 o codificación URL) en lugar de puntos de entrada en un gran lío de dependencias lógicas (como HTTP), encontrará que es completamente práctico para hacer lo correcto con las dependencias genuinas.
fuente
Definitivamente esta es una pregunta / respuesta obvia, pero por lo que vale, pensé en invertir mis dos centavos. En términos del estilo de TDD, el método 2 es definitivamente el enfoque que sigue a la letra. El argumento para el método 2 es que si alguna vez quisiste reemplazar la implementación de una de esas clases, digamos una
ImageIO
biblioteca equivalente, entonces podrías hacerlo mientras mantienes la confianza en las clases que aprovechan ese código.Sin embargo, como mencionó, si usa muchos métodos estáticos, terminará escribiendo mucho código contenedor. Esto podría no ser algo malo a largo plazo. En términos de mantenibilidad, ciertamente hay argumentos para esto. Personalmente, preferiría este enfoque.
Dicho esto, PowerMock existe por una razón. Es un problema bastante conocido que probar cuando hay métodos estáticos involucrados es muy doloroso, de ahí el inicio de PowerMock. Creo que debe sopesar sus opciones en términos de cuánto trabajo será envolver todas sus clases de ayuda frente al uso de PowerMock. No creo que sea 'darse por vencido' usar PowerMock, solo siento que envolver las clases le permite una mayor flexibilidad en un proyecto grande. Cuantos más contratos públicos (interfaces) pueda proporcionar, más limpia será la separación entre intención e implementación.
fuente
Como referencia para todos los que también están lidiando con este problema y se encuentran con esta pregunta, voy a describir cómo decidimos abordar el problema:
Básicamente estamos siguiendo la ruta descrita como # 2 (clases de contenedor para utilidades estáticas). Pero solo los usamos cuando es demasiado complejo proporcionar a la utilidad los datos requeridos para producir la salida deseada (es decir, cuando absolutamente tenemos que burlarnos del método).
Esto significa que no tenemos que escribir un contenedor para una utilidad simple como Apache Commons
StringEscapeUtils
(porque las cadenas que necesitan pueden proporcionarse fácilmente) y no usamos simulacros para métodos estáticos (si creemos que podríamos necesitarlo, es hora de escribir una clase de contenedor y luego se burlan de una instancia del contenedor).fuente
Probaría estas clases usando Groovy . Groovy es fácil de agregar a cualquier proyecto Java. Con él, puedes burlarte de los métodos estáticos con bastante facilidad. Vea Métodos estáticos burlones usando Groovy para ver un ejemplo.
fuente
Trabajo para una importante compañía de seguros y nuestro código fuente sube a 400 MB de archivos java puros. Hemos estado desarrollando toda la aplicación sin pensar en TDD. A partir de enero de este año comenzamos con pruebas de junit para cada componente individual.
La mejor solución en nuestro departamento era usar objetos Mock en algunos métodos JNI que eran confiables para el sistema (escritos en C) y, como tal, no podía estimar exactamente los resultados cada vez en cada sistema operativo. No teníamos otra opción que usar clases simuladas e implementaciones específicas de métodos JNI específicamente con el propósito de probar cada módulo individual de la aplicación para cada sistema operativo que admitimos.
Pero fue realmente rápido y ha funcionado bastante bien hasta ahora. Lo recomiendo: http://www.easymock.org/
fuente
Los objetos interactúan entre sí para lograr un objetivo, cuando tiene un objeto difícil de probar debido al entorno (un punto final de servicio web, una capa de dao que accede a la base de datos, los controladores que manejan los parámetros de solicitud http) o si desea probar su objeto de forma aislada, luego te burlas de esos objetos.
la necesidad de burlarse de los métodos estáticos es un mal olor, debe diseñar su aplicación más orientada a objetos, y los métodos estáticos de utilidad de prueba de unidad no agregan mucho valor al proyecto, la clase de envoltura es un buen enfoque dependiendo de la situación, pero intente para probar aquellos objetos que usan los métodos estáticos.
fuente
A veces uso la opción 4
Algo como esto.
Lo que me gusta de este enfoque es que mantiene los métodos de utilidad estáticos, lo que me parece correcto cuando intento usar la clase en todo el código.
fuente