unit tutorial tests test make how examples example español create java unit-testing testing junit

java - tests - junit tutorial



junit & java: prueba de métodos no públicos (17)

JUnit solo probará aquellos métodos en mi clase que sean públicos. ¿Cómo hago las pruebas junit en las que no son (es decir, privadas, protegidas)?

Puedo probarlos al no usar junit, pero me preguntaba cuál era el método estándar de junit.


Jarra DP4j

Para probar métodos privados, necesitamos usar la reflexión y se apunta en todas las respuestas.

bien ahora esta tarea se simplifica con la ayuda de Dp4j jar.

  • Dp4j analiza su código y genera automáticamente el código de Reflection API para usted.

  • Simplemente agregue dp4j.jar a su CLASSPATH.

  • Dp4j.jar contiene procesadores de anotación, buscarán los métodos en su código que están anotados con @Test JUnit anotación.

  • Dp4j analiza el código de esos métodos, y si descubre que está accediendo ilegalmente a métodos privados, reemplazará su referencia de método privado no válido con un código equivalente que use la API Reflection de Java.

Obtenga más detalles here


Aquí está el método "probablemente no debería hacerlo de esta manera" que todos los demás siguen insistiendo contigo. Sin embargo, creo que está dentro del campo de la posibilidad de que haya razones para hacerlo de esta manera. El siguiente código tendrá acceso a un campo privado, pero el código para un método privado es casi idéntico.

public void testPrivateField() throws InterruptedException { Class<ClassWPrivateField> clazz = ClassWPrivateField.class; try { Field privateField = clazz.getDeclaredField("nameOfPrivateField"); privateField.setAccessible(true); // This is the line // do stuff } catch(NoSuchFieldException nsfe) { nsfe.printStackTrace(); fail(); } catch(IllegalAccessException iae) { iae.printStackTrace(); fail(); } }


Busque "PrivateAccessor.invoke". Mi código lo importa de "junitx.util", pero no sé de dónde vino.


Casi siempre uso Spring en mis proyectos Java y, como tal, mis objetos están diseñados para la inyección de dependencias. Tienden a ser implementaciones bastante granulares de interfaces públicas que se ensamblan dentro del contexto de la aplicación. Como tal, rara vez (o nunca) tengo la necesidad de probar métodos privados porque la clase en sí misma es lo suficientemente pequeña como para que simplemente no sea un problema.

Incluso cuando no uso Spring, tiendo a adoptar las mismas prácticas de ensamblar objetos pequeños y simples en abstracciones cada vez más grandes, cada una de las cuales es relativamente simple pero compleja por los objetos agregados.

En mi experiencia, tener la necesidad de probar los métodos privados es un indicador de que lo que estás probando podría (y debería) ser simplificado.

Siendo así, si todavía sientes realmente la necesidad:

  • Los métodos protegidos pueden probarse por subclases;
  • Los métodos privados del paquete pueden probarse poniendo las pruebas unitarias en el mismo paquete; y
  • Los métodos privados se pueden probar en unidades al proporcionar, por ejemplo, un método de proxy de fábrica privado de paquete. No es ideal, pero privado significa privado.

Como con muchos problemas de pruebas unitarias, probar métodos privados es en realidad un problema de diseño disfrazado. En lugar de tratar de hacer algo complicado para probar métodos privados, cuando me apetece escribir pruebas para métodos privados, me tomo un minuto para preguntarme: "¿Cómo necesitaría diseñar esto para poder probarlo a fondo a través de métodos públicos?"

Si eso no funciona, JUnitX permite probar métodos privados, aunque creo que solo está disponible para JUnit 3.8.


Como una especie de derivación de esto, y no estoy seguro de a quién se debe toda la cuestión de la "programación de políglotas", pero las pruebas de Groovy se pueden ejecutar en Junit e ignoran todo el asunto público / no público. Nota al pie, oficialmente se clasificó como un "error", pero cuando intentaron arreglarlo, hubo una tormenta tal que se volvió a poner como originalmente era.


Cuando escribes una prueba JUnit, tienes que hacer un cambio mental sutil: "Ahora soy cliente de mi propia clase". Eso significa que lo privado es privado, y usted solo prueba el comportamiento que ve el cliente.

Si el método realmente debe ser privado, lo consideraría una falla de diseño para hacerlo visible solo por el bien de las pruebas. Debe poder inferir su operación correcta en función de lo que ve el cliente.

En los tres años transcurridos desde que escribí esto originalmente, comencé a abordar el problema de forma ligeramente diferente, utilizando la reflexión de Java.

El pequeño y sucio secreto es que puedes probar métodos privados en JUnit tal como lo harías con los públicos, usando la reflexión. Puede probar el contenido de su corazón y aún así no exponerlo como público para los clientes.


De acuerdo con casi todas las publicaciones, probablemente debería refactorizar y probablemente no realizar pruebas privadas, excepto a través del público, solo quería agregar una forma diferente de pensarlo ...

Piensa en tu clase como una "Unidad", no como un método. Está probando la clase y puede mantener un estado válido independientemente de cómo se llamen los métodos públicos.

Llamar a métodos privados puede destruir la encapsulación e invalidar las pruebas.


Esto realmente no está publicado como una respuesta, más que he encontrado el mismo problema, y ​​el "si necesita ser privado, probablemente debería ser refactorizado" no me sienta bien.

Supongamos que tiene un tipo de funcionalidad que desea separar de alguna manera interna de la clase. Por ejemplo, supongamos que tengo algo como esto:

public class HolderOfSomeStrings{ private List<String> internal_values; public List<String> get() { List<String> out = new ArrayList<String>(); for (String s:internal_values) { out.add(process(s)); } return get; } private static String process(String input) { //do something complicated here that other classes shouldn''t be interested in } }

El punto aquí es que junit me obliga a hacer público el proceso, o al menos protegerlo, o ponerlo en su propia clase de utilidad. Pero si se trata de algún tipo de lógica interna de HolderOfSomeStrings, no tengo claro que esto sea correcto, me parece que esto debe ser privado, y hacerlo más visible encierra el código de alguna manera.


Estoy absolutamente de acuerdo con @duffymo en que el código debe ser probado desde la vista del cliente (aunque él dice que dejó de pensar de esta manera). Sin embargo, desde este punto de vista, privado vs otros tienen diferentes significados. El cliente de un método privado es la clase en sí misma, por lo que prefiero probarlos a través de la API externa (pública / protegida por paquete). Sin embargo, los miembros protegidos y protegidos por paquetes están ahí para los clientes externos, por lo que los pruebo con falsificaciones que heredan la clase propietaria o que residen en el mismo paquete.


La solución más simple es poner las pruebas JUnit en el mismo paquete (pero diferente directorio) y usar visibilidad predeterminada (es decir, paquete privado) para los métodos.

Otro enfoque más complicado es utilizar la reflexión para acceder a métodos privados.


Para tomar prestado un pensamiento de Andy Hunt, incluso sus métodos privados deben tener algún efecto secundario que le interese. En otras palabras, deben ser llamados desde algún método público y realizar una tarea interesante que ocasione que el estado de su objeto cambie. . Prueba para ese cambio de estado.

Supongamos que tiene el método público pubMethod y el método privado privMethod. Cuando llamas a pubMethod, a su vez llama a privMethod para realizar una tarea (tal vez analizar una Cadena). El método pubMethod utiliza esta cadena analizada para establecer los valores de las variables miembro de alguna manera o para influir en su propio valor de retorno. Realice una prueba observando el efecto deseado en el valor de retorno de pubMethod o en las variables de los miembros (posiblemente mediante el uso de accesadores para acceder a ellos).


Por lo general, no prueba métodos privados porque solo pueden (normalmente) probarse indirectamente a través de otro método público. Cuando realiza pruebas de manejo y crea métodos privados, generalmente son el resultado de una refactorización de "método de extracción" y ya se han probado de forma indirecta.

Si le preocupa probar un método privado con mucha lógica, lo más inteligente que puede hacer es mover ese código a otra clase en un método público. Una vez que haya hecho eso, el método anterior que usó este código puede tener sus pruebas simplificadas al tener la funcionalidad provista por un stub o un simulacro.


Puede usar TestNG en lugar de JUnit, que no se preocupa de que el método sea privado o público.


Si tiene una cantidad significativa de lógica enterrada en relativamente pocos puntos de entrada "Públicos", probablemente esté violando el Principio de Responsabilidad Individual . Si es posible, querrás refactorizar el código en múltiples clases, lo que finalmente conducirá a más métodos "públicos" para probar.


Una escuela de pensamiento sobre las pruebas unitarias dice que solo debes poder probar los métodos públicos, ya que solo debes probar la API pública y, al hacerlo, debes cubrir el código en tus métodos no públicos. Su experiencia puede ser diferente; Me parece que esto es a veces el caso y, a veces no.

Dicho esto, hay un par de formas de probar métodos no públicos:

  • Puede probar métodos protegidos y de ámbito de paquete colocando las pruebas de su unidad en el mismo paquete que las clases que están probando. Esta es una práctica bastante común.
  • Puede probar métodos protegidos de pruebas unitarias en otro paquete creando una subclase de la clase bajo prueba que anula los métodos que desea probar como públicos, y que esos métodos reemplazados invoquen los métodos originales con la palabra clave super. Normalmente, esta "subclase de prueba" sería una clase interna en la clase JUnit TestCase que realiza la prueba. Esto es un poco más hacky, en mi opinión, pero lo he hecho.

Espero que esto ayude.


Use la reflexión como se indicó anteriormente para probar métodos privados. Si estamos siguiendo TDD, deberíamos probar métodos privados dado que TDD implica que no habría sorpresas más adelante. Entonces uno no debería esperar para terminar su método público para probar partes privadas. Y esto ayuda a realizar pruebas de regresión más granulares al volver a factorizar.