¿Cómo pruebo una clase que tiene métodos, campos o clases internas privadas?
¿Cómo uso JUnit para probar una clase que tiene métodos privados internos, campos o clases anidadas?
Parece malo cambiar el modificador de acceso de un método solo para poder ejecutar una prueba.
Si tiene una aplicación Java heredada y no puede cambiar la visibilidad de sus métodos, la mejor manera de probar métodos privados es utilizar la reflexión .
Internamente utilizamos ayudantes para obtener/establecer private
variables private static
, así como para invocar private
métodos private static
. Los siguientes patrones le permitirán hacer prácticamente cualquier cosa relacionada con los métodos y campos privados. Por supuesto, no se pueden cambiar private static final
las variables mediante la reflexión.
Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);
Y para campos:
Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
Notas:
TargetClass.getDeclaredMethod(methodName, argClasses)
le permite buscarprivate
métodos. Lo mismo se aplica paragetDeclaredField
.- Se
setAccessible(true)
requiere que juegue con los soldados rasos.
La mejor manera de probar un método privado es mediante otro método público. Si esto no se puede hacer, entonces se cumple una de las siguientes condiciones:
- El método privado es código muerto.
- Hay un olor a diseño cerca de la clase que estás probando.
- El método que estás intentando probar no debe ser privado.
Cuando tengo métodos privados en una clase que son lo suficientemente complicados como para sentir la necesidad de probar los métodos privados directamente, eso huele a código: mi clase es demasiado complicada.
Mi enfoque habitual para abordar estos problemas es crear una nueva clase que contenga las partes interesantes. A menudo, este método y los campos con los que interactúa, y tal vez uno o dos métodos más, se pueden extraer en una nueva clase.
La nueva clase expone estos métodos como "públicos", por lo que son accesibles para pruebas unitarias. Las clases nueva y antigua ahora son más simples que la clase original, lo cual es excelente para mí (¡tengo que mantener las cosas simples o me pierdo!).
Tenga en cuenta que no estoy sugiriendo que las personas creen clases sin usar su cerebro. El punto aquí es utilizar las fuerzas de las pruebas unitarias para ayudarle a encontrar buenas clases nuevas.
He utilizado la reflexión para hacer esto para Java en el pasado y, en mi opinión, fue un gran error.
Estrictamente hablando, no debería escribir pruebas unitarias que prueben directamente métodos privados. Lo que deberías estar probando es el contrato público que la clase tiene con otros objetos; nunca debes probar directamente las partes internas de un objeto. Si otro desarrollador quiere realizar un pequeño cambio interno en la clase, que no afecte el contrato público de la clase, entonces tendrá que modificar su prueba basada en reflexión para asegurarse de que funcione. Si hace esto repetidamente a lo largo de un proyecto, las pruebas unitarias dejan de ser una medida útil del estado del código y comienzan a convertirse en un obstáculo para el desarrollo y una molestia para el equipo de desarrollo.
Lo que recomiendo hacer en su lugar es utilizar una herramienta de cobertura de código, como Cobertura , para garantizar que las pruebas unitarias que escriba proporcionen una cobertura decente del código en métodos privados. De esa manera, prueba indirectamente lo que están haciendo los métodos privados y mantiene un mayor nivel de agilidad.