2011-08-02 11 views
63

Quién tiene una solución para esa necesidad común.anotación para hacer que un método privado sea público solo para las clases de prueba

Tengo una clase en mi aplicación.

algunos métodos son públicos, ya que son parte de la API, y algunos son privados, ya que para el uso interno de hacer que el flujo interno más legible

ahora, dicen que quiero escribir una prueba unitaria, o más como una prueba de integración, que se ubicará en un paquete diferente, que se le permitirá llamar a este método, PERO, quiero que la llamada normal a este método no se permitirá si intenta llamar desde clases de la aplicación sí

así, yo estaba pensando en algo así

public class MyClass { 

    public void somePublicMethod() { 
    .... 
    } 

    @PublicForTests 
    private void somePrivateMethod() { 
    .... 
    } 
} 

La anotación anterior marcará el método privado como "públicos para las pruebas" lo que significa, se permitirá que la compilación y tiempo de ejecución para cualquier clase que se encuentra bajo la prueba de ... paquete, mientras que la compilación y \ o de tiempo de ejecución se producirá un error de cualquier clase que no esté bajo el paquete de prueba.

alguna idea? ¿hay una anotación como esta? ¿hay una mejor manera de hacer esto?

parece que la más pruebas de unidad que se escribe, a su más reforzado para romper su encapsulación ...

+0

¿por qué no utilizar la reflexión para acceder al método privado? – chance

Respuesta

3

Un artículo sobre Testing Private Methods expone algunos enfoques para probar código privado. el uso de la reflexión impone una carga adicional al programador para recordar que, si se realiza la refactorización, las cadenas no cambian automáticamente, pero creo que es el enfoque más limpio.

89

La forma más común es hacer que el método privado protegido o paquete-privada y poner la unidad de prueba para este método en el mismo paquete que la clase bajo prueba. Guava tiene un @VisibleForTesting annotation, pero es sólo para fines de documentación.

+9

+1 para usar el mismo paquete –

+14

Si usa FindBugs, he creado [un complemento que realmente puede verificar] (https://github.com/Monits/findbugs-plugin) para usted que los métodos '@ VisibleForTesting' son no se usa fuera de las clases de prueba. – Johnco

10

Considere el uso de interfaces para exponer los métodos API, utilizando fábricas o DI para publicar los objetos de manera que los consumidores los conozcan solo mediante la interfaz. La interfaz describe la API publicada. De esta forma, puede hacer que lo que desee público en los objetos de implementación y los consumidores de ellos vean solo los métodos expuestos a través de la interfaz.

1

No puede hacer esto, ¿cómo podría compilar sus pruebas? El compilador no tomará la anotación en cuenta.

Hay dos enfoques generales para este

La primera es utilizar la reflexión para tener acceso a los métodos de todos modos

El segundo es utilizar el paquete-privada en lugar de privada, y luego tener sus pruebas en el mismo paquete (pero en un módulo diferente). En esencia, serán privados para otro código, pero sus pruebas aún podrán acceder a ellos.

Por supuesto, si realiza pruebas de caja negra, no debe acceder a los miembros privados de todos modos.

14

Si la cobertura de su prueba es buena en todos los métodos públicos dentro de la clase probada, los métodos privados llamados por el público se probarán automáticamente ya que hará valer todo el posible caso.

El JUnit Doc dice:

métodos privados de análisis pueden ser una indicación de que esos métodos deben ser movidos a otra clase para promover la reutilización. Pero si debe ... Si está utilizando JDK 1.3 o una versión superior, puede usar la reflexión para subvertir el mecanismo de control de acceso con la ayuda del PrivilegedAccessor. Para más detalles sobre cómo usarlo, read this article.

2

O puede extraer este método en cierta estrategia objeto. En este caso, puede probar fácilmente la clase extraída y no hacer que el método sea público o algo mágico con reflection/bytecode.

0

Por lo que sé, no hay anotaciones como esta. La mejor manera es usar la reflexión como sugirieron algunos de los otros. Mira esta publicación:
How do I test a class that has private methods, fields or inner classes?

Solo debes tener cuidado al probar el resultado de excepción del método. Por ejemplo: si espera una IllegalArgumentException, pero en cambio obtendrá "null" (Clase: java.lang.reflect.InvocationTargetException).
Un colegue mío propuso utilizar el powermock framework para estas situaciones, pero todavía no lo he probado, por lo que no tengo idea de qué es exactamente lo que puede hacer. Aunque he utilizado el framework Mockito en el que se basa y eso también es un buen marco (pero creo que no resuelve el problema de la excepción del método privado).

Es una gran idea tener la anotación @PublicForTests.

¡Salud!

4

dp4j tiene lo que necesita. Esencialmente, todo lo que tiene que hacer es agregar dp4j a su classpath y siempre que un método anotado con @Test (anotación de JUnit) llame a un método que sea privado funcionará (dp4j inyectará la reflexión requerida en tiempo de compilación). También puede usar la anotación @TestPrivates de dp4j para ser más explícito.

Si insiste en anotar también sus métodos privados, puede usar la anotación @VisibleForTesting de Google.

1

Recientemente hemos lanzado una biblioteca que ayuda mucho para tener acceso a campos privados, métodos y clases internas través de la reflexión: BoundBox

Para una clase como

public class Outer { 
    private static class Inner { 
     private int foo() {return 2;} 
    } 
} 

proporciona una sintaxis como:

Outer outer = new Outer(); 
Object inner = BoundBoxOfOuter.boundBox_new_Inner(); 
new BoundBoxOfOuter.BoundBoxOfInner(inner).foo(); 

Lo único que debe hacer para crear la clase BoundBox es escribir @BoundBox(boundClass=Outer.class) y la clase BoundBoxOfOuter se generará instantáneamente.

1

Bien, entonces aquí tenemos dos cosas que están siendo mezcladas.Lo primero, es cuando necesita marcar algo para usarlo solo en la prueba, lo que estoy de acuerdo con @JB Nizet, usar la anotación de guayaba sería bueno.

Otra cosa es probar métodos privados. ¿Por qué deberías probar métodos privados desde afuera? Quiero decir ... Deberías poder probar el objeto por sus métodos públicos y, al final, su comportamiento. Al menos, eso estamos haciendo e intentando enseñar a los desarrolladores junior, que siempre intentan probar métodos privados (como una buena práctica).

Cuestiones relacionadas