¿Cómo hace una prueba unitaria de los métodos privados?

165

Estoy trabajando en un proyecto java. Soy nuevo en la prueba de unidad. ¿Cuál es la mejor manera de probar por unidad los métodos privados en clases java?

    
pregunta Vinoth Kumar C M 14.08.2011 - 06:44

10 respuestas

224

Por lo general, no prueba los métodos privados de forma directa. Ya que son privados, considérelos un detalle de implementación. Nadie va a llamar a uno de ellos y esperar que funcione de una manera particular.

En su lugar, debería probar su interfaz pública. Si los métodos que llaman a sus métodos privados funcionan como espera, entonces asume por extensión que sus métodos privados funcionan correctamente.

    
respondido por el Adam Lear 14.08.2011 - 07:40
110

En general, lo evitaría. Si su método privado es tan complejo que necesita una prueba de unidad por separado, a menudo significa que se merece su propia clase. Esto puede alentarlo a escribirlo de una manera que sea reutilizable. Luego, debe probar la nueva clase y llamar a la interfaz pública de ésta en su clase anterior.

Por otra parte, a veces los detalles de la implementación en clases separadas llevan a clases con interfaces complejas, a una gran cantidad de datos que pasan entre la clase antigua y la nueva, oa un diseño que puede verse bien desde el punto de vista de la POO. pero no coincide con las intuiciones provenientes del dominio del problema (por ejemplo, dividir un modelo de precios en dos partes solo para evitar probar métodos privados no es muy intuitivo y puede ocasionar problemas más adelante al mantener / extender el código). No quieres tener "clases gemelas" que siempre se cambian juntas.

Cuando me enfrento a una elección entre encapsulación y comprobabilidad, prefiero la segunda. Es más importante tener el código correcto (es decir, producir la salida correcta) que un buen diseño de POO que no funcione correctamente, porque no se probó adecuadamente. En Java, simplemente puede dar acceso al método "predeterminado" y poner la prueba de la unidad en el mismo paquete. Las pruebas unitarias son simplemente parte del paquete que está desarrollando, y está bien tener una dependencia entre las pruebas y el código que se está probando. Esto significa que cuando cambie la implementación, es posible que deba cambiar sus pruebas, pero eso está bien: cada cambio de la implementación requiere volver a probar el código, y si las pruebas deben modificarse para hacer eso, simplemente haga lo siguiente. it.

En general, una clase puede ofrecer más de una interfaz. Hay una interfaz para los usuarios y una interfaz para los mantenedores. El segundo puede exponer más para garantizar que el código se haya probado adecuadamente. No tiene que ser una prueba de unidad en un método privado, podría ser, por ejemplo, el registro. El registro también "rompe la encapsulación", pero todavía lo hacemos, porque es muy útil.

    
respondido por el quant_dev 14.08.2011 - 10:18
26

La prueba de los métodos privados dependería de su complejidad; algunos métodos privados de una línea no justificarían realmente el esfuerzo extra de las pruebas (esto también se puede decir de los métodos públicos), pero algunos métodos privados pueden ser tan complejos como los métodos públicos y difíciles de probar a través de la interfaz pública. p>

Mi técnica preferida es hacer que el paquete del método privado sea privado, lo que permitirá el acceso a una prueba de unidad en el mismo paquete, pero aún será encapsulado desde el resto del código. Esto le dará la ventaja de probar la lógica del método privado directamente en lugar de tener que confiar en una prueba de método público para cubrir todas las partes de la lógica (posiblemente) compleja.

Si está emparejado con la anotación @Visiblestrongsting en la biblioteca de Google Guava, claramente está marcando este método privado del paquete como visible solo para la prueba y, como tal, no debería ser llamado por ninguna otra clase.

Los opositores de esta técnica argumentan que esto romperá la encapsulación y abrirá los métodos privados para codificar en el mismo paquete. Aunque estoy de acuerdo en que esto rompe la encapsulación y abre el código privado a otras clases, sostengo que probar la lógica compleja es más importante que la encapsulación estricta y no usar métodos privados de paquetes que están claramente marcados tan visible para las pruebas solo debe ser responsabilidad de los desarrolladores que usan y cambian la base del código.

Método privado antes de la prueba:

private int add(int a, int b){
    return a + b;
}

Método privado del paquete listo para la prueba:

@VisibleForTesting
int add(int a, int b){
    return a + b;
}

Nota: Poner pruebas en el mismo paquete no es equivalente a ponerlas en la misma carpeta física. Separar el código principal y el código de prueba en estructuras de carpetas físicas separadas es una buena práctica en general, pero esta técnica funcionará siempre que las clases estén definidas en el mismo paquete.

    
respondido por el Richard 27.11.2012 - 11:43
14

Si no puede usar las API externas o no quiere hacerlo, aún puede usar la API JDK estándar pura para acceder a métodos privados utilizando la reflexión. Aquí hay un ejemplo

MyObject obj = new MyObject();
Method privateMethod = MyObject.class.getDeclaredMethod("getFoo", null);
privateMethod.setAccessible(true);
String returnValue = (String) privateMethod.invoke(obj, null);
System.out.println("returnValue = " + returnValue);

Consulte el tutorial de Java enlace o la API de Java enlace para obtener más información.

Como @kij citó en su respuesta, hay veces en que una solución simple que utiliza la reflexión es realmente buena para probar un método privado.

    
respondido por el Gustavo Coelho 31.01.2014 - 13:10
9

Caso de prueba de unidad significa probar la unidad de código. No significa probar la interfaz porque si está probando la interfaz, eso no significa que esté probando la unidad de código. Se convierte en una especie de caja negra de prueba. Además, es mejor encontrar problemas en el nivel de unidad más pequeño que determinar los problemas en el nivel de interfaz y luego tratar de depurar qué pieza no estaba funcionando. Por lo tanto, el caso de prueba unitaria debe probarse independientemente de su alcance. A continuación hay una forma de probar métodos privados.

Si está utilizando java, puede usar jmockit que proporciona Deencapsulation.invoke para llamar a cualquier método privado de la clase bajo prueba. Utiliza la reflexión para llamarlo eventualmente, pero proporciona una envoltura agradable a su alrededor. ( enlace )

    
respondido por el agrawalankur 05.02.2014 - 04:07
8

Primero que todo, como sugirieron otros autores: piense dos veces si realmente necesita probar el método privado. Y si es así, ...

En .NET puede convertirlo en un método "Interno" y hacer un paquete " InternalVisible " a su proyecto de prueba de unidad.

En Java puede escribir pruebas en la clase que se va a probar y sus métodos de prueba también deberían poder llamar a métodos privados. Realmente no tengo una gran experiencia con Java, por lo que probablemente no sea la mejor práctica.

Gracias.

    
respondido por el Budda 12.04.2012 - 20:19
7

Por lo general hago tales métodos protegidos. Digamos que tu clase está en:

src/main/java/you/Class.java

Puedes crear una clase de prueba como:

src/test/java/you/TestClass.java

Ahora tiene acceso a métodos protegidos y puede probarlos por unidad (JUnit o TestNG realmente no importan), pero mantiene estos métodos de las personas que llaman que no deseaba.

Tenga en cuenta que esto espera un árbol de fuentes de estilo experto.

    
respondido por el gyorgyabraham 13.12.2013 - 11:52
3

Si realmente necesitas probar un método privado, con Java quiero decir, puedes usar fest assert y / o fest reflect . Utiliza la reflexión.

Importe la biblioteca con maven (las versiones dadas no son las más recientes que creo) o impórtela directamente en su classpath:

<dependency>
     <groupId>org.easytesting</groupId>
     <artifactId>fest-assert</artifactId>
     <version>1.4</version>
    </dependency>

    <dependency>
     <groupId>org.easytesting</groupId>
     <artifactId>fest-reflect</artifactId>
    <version>1.2</version>
</dependency>

Como ejemplo, si tiene una clase llamada 'MyClass' con un método privado llamado 'myPrivateMethod' que toma una cadena como parámetro y actualiza su valor a 'esto es una prueba genial', puede hacer la siguiente prueba junit :

import static org.fest.reflect.core.Reflection.method;
...

MyClass objectToTest;

@Before
public void setUp(){
   objectToTest = new MyClass();
}

@Test
public void testPrivateMethod(){
   // GIVEN
   String myOriginalString = "toto";
   // WHEN
   method("myPrivateMethod").withParameterTypes(String.class).in(objectToTest).invoke(myOriginalString);
   // THEN
   Assert.assertEquals("this is cool testing !", myOriginalString);
}

Esta biblioteca también le permite reemplazar las propiedades de los beans (sin importar que sean privadas y que no haya escritores configurados) por un simulacro, y usar esto con Mockito o cualquier otro marco simulado es realmente genial. Lo único que debe saber en este momento (no sé si esto será mejor en las próximas versiones) es el nombre del campo / método objetivo que desea manipular y su firma.

    
respondido por el kij 27.11.2012 - 10:45
2

Lo que normalmente hago en C # es hacer que mis métodos estén protegidos y no privados. Es un modificador de acceso un poco menos privado, pero oculta el método de todas las clases que no heredan de la clase en prueba.

public class classUnderTest
{
   //this would normally be private
   protected void methodToTest()
   {
     //some code here
   }
}

Cualquier clase que no herede directamente de classUnderTest no tiene idea de que incluso methodToTest existe. En mi código de prueba, puedo crear una clase de prueba especial que se extiende y proporciona acceso a este método ...

class TestingClass : classUnderTest
{
   public void methodToTest()
   {
     //this returns the method i would like to test
     return base.methodToTest();
   }
}

Esta clase solo existe en mi proyecto de prueba. Su único propósito es proporcionar acceso a este método único. Me permite acceder a lugares que la mayoría de las otras clases no tienen.

    
respondido por el spaceman 09.05.2013 - 11:16
0

Puede probar métodos privados fácilmente si coloca sus pruebas de unidad en una clase interna en la clase que está evaluando. Usando TestNG, las pruebas unitarias deben ser clases internas públicas estáticas anotadas con @Test, como esto:

@Test
public static class UserEditorTest {
    public void test_private_method() {
       assertEquals(new UserEditor().somePrivateMethod(), "success");
    }
}

Ya que es una clase interna, se puede llamar al método privado.

Mis pruebas se ejecutan desde Maven y encuentra automáticamente estos casos de prueba. Si solo quieres probar una clase, puedes hacerlo

$ mvn test -Dtest=*UserEditorTest

Fuente: enlace

    
respondido por el Roger Keays 10.04.2013 - 22:44

Lea otras preguntas en las etiquetas