2012-01-25 19 views
11

Así que soy extremadamente nuevo en las pruebas de software, y estoy buscando agregar un par de pruebas a una de mis aplicaciones. Tengo un método público addKeywords() que a lo largo del camino llama a un método privado removeInvalidOperations(). Este método privado realiza llamadas a una API externa y tiene ~ 50 líneas de código. Como considero que este es un método algo complejo, me gustaría probar esto sin tener que hacerlo al llamar al método addKeyword(). Sin embargo, esto no parece posible (al menos no aunque JUnit).Quiero probar un método privado: ¿hay algún problema con mi diseño?

La información que he analizado sugiere que el deseo de probar los métodos privados podría ser un olor a código. Algunas personas sugieren que puede ser una señal de que esto debe refactorizarse en una clase separada y hacerse público. Además, hay sugerencias de que si realmente lo necesita, puede realizar modificaciones en su código de producción, p. cambiar la visibilidad del método privado.

Realmente no veo por qué tengo un problema con mi diseño de código actual, pero tampoco me gusta la idea de editar mi código de producción para adaptarlo a mis necesidades de prueba.

Como digo, soy bastante nuevo en las pruebas, por lo que cualquier ayuda es muy apreciada. Además, avíseme si hay más información que pueda proporcionar para ayudar con las respuestas.

+0

Una solución rápida que he usado a menudo es cambiar el acceso de privado a predeterminado (paquete) y comentar '// acceso de paquete para pruebas unitarias solamente. Si esto es aceptable depende de sus estándares de codificación y de cuánto confíe sus compañeros programadores entienden que este método, incluso si el paquete tiene acceso, no es una "API real". – user949300

Respuesta

13

Sugiero refactorizarlo.

La información que he examinado sugiere que el deseo de probar métodos privados podría ser un olor a código. Algunas personas sugieren que puede ser una señal de que esto se debe refactorizar en una clase separada y hacerse pública.

Ha cubierto las diversas razones a favor y en contra en su propia pregunta, parece estar al tanto de los argumentos. Pero tienes un método que parece bastante complicado e implica una API externa. Eso vale la pena probarlo solo.removeInvalidOperations() puede seguir siendo un método privado en la clase en la que se encuentra, pero básicamente delegaría en otra dependencia.

class YourClass 
{ 
    private OperationRemover remover; 

    public void addKeywords() { 
     // whatever 
     removeInvalidOperations(); 
    } 

    private void removeInvalidOperations() { 
     remover.remove(); 
    } 
} 

Esto le da la ventaja añadida de ser capaz de sustituir esta dependencia en algún momento, incluyendo la posibilidad de poner a prueba su método addKeywords() sin tener que hacer una llamada de API externa, lo que haría más fácil probar ese método.OperationRemover podría ser una interfaz, por ejemplo, y para fines de prueba, simplemente debe pasar un talón en su lugar en lugar de la versión concreta utilizada en la producción. En cuanto a su versión concreta, puede escribir pruebas independientemente de lo que esté sucediendo con su clase existente.

Realmente no veo por qué tengo un problema con mi diseño de código actual, sino también no me gusta la idea de la edición de mi código de producción para satisfacer mis necesidades pruebas.

La capacidad de prueba más fácil es una ventaja secundaria. Mírelo de otra manera: lo que en realidad está haciendo es hacer que el código sea poco flexible y extensible. Arriba, hemos separado la llamada a la API externa del código que podría necesitar usar el resultado. La API externa podría cambiar. Puede pasar de un servicio a otro, pero el código que utiliza el resultado no tiene que importarle. Esa clase puede permanecer igual, solo la clase que realmente coloca las llamadas necesita ser modificada (o reemplazada).

Ejemplo del mundo real: El año es 2007 y trabajas para un banco en un gran centro financiero en los Estados Unidos. Su aplicación necesita usar información de cuenta. Su código llega a un servicio web de algún tipo dentro del banco y obtiene la información que necesita, en la forma que necesita, y luego continúa con su procesamiento. En 2008, el sector financiero de Estados Unidos implosiona, y su banco (que está al borde del colapso) es engullido por otro banco. Su aplicación se salva, excepto que ahora tiene que contactarse con una API diferente que ya existe dentro del banco sobreviviente para obtener información de la cuenta desde allí. ¿Debe cambiar el código que consume esta información de cuenta? No necesariamente. Es la misma información de cuenta que antes, solo de una fuente diferente. No, todo lo que necesita cambiar es la implementación que invoca las API. El consumo de código nunca tiene que saberlo.

El hecho de que tal acoplamiento flojo también promueve y facilita las pruebas es una ventaja.

+0

¡Gracias por una respuesta tan detallada! Eso realmente me ayudó a entender algunos de los beneficios de tal enfoque. – QuakerOat

7

Si es private, no puede considerarse parte de la API de su aplicación, por lo que probarlo es realmente un olor a código: cuando la prueba se rompe, ¿está bien o no?

Las pruebas unitarias se supone que son funcionalidad orientada, no código orientado. Prueba unidades de funcionalidad, no unidades de código.

Independientemente de la filosofía, una clase fuera de su implementación no puede acceder al método privado sin hackear la JVM, por lo que no tiene suerte. O bien tiene que cambiar la visibilidad del método, hacer una prueba de unidad protected. la clase extiende, o prueba la función indirectamente llamando los métodos públicos que hacen uso de ella.

0

Si no quiere llamar al addKeywords(), tal vez debería simplemente agregar otro método público testRemoveInvalidOperations(), que solo llama al privado removeInvalidOperations(). Puede eliminar la prueba en una fecha posterior.

+0

+1 No es una mala idea. Cambio menor: haga que testRemoveInvalidOperations() tenga acceso predeterminado (paquete) y agregue un comentario relevante para aclarar que su propósito es solo para pruebas unitarias. – user949300

+0

-1 Nunca es una buena idea hacer agujeros en el código solo para probar. Tienes que probar lo que tienes, no lo que quieres tener. Además, las buenas pruebas tienden a exigir un buen diseño. Si la prueba quiere que la refactorice, probablemente sea la correcta. Y probar un código complicado es más que justo. – pkoch

+0

Es cierto que debe asegurarse de eliminar el código de prueba antes de liberar los archivos al público. ¡Dejar el código público es una mala idea! – Daniel

4

Normalmente no querrá probar un método privado, pero hay excepciones.

Usted puede verse tentado a probar un método privado si:

  1. No ha pensado cuidadosamente acerca de cómo probar el método privado indirectamente llamando a los métodos públicos existentes.

  2. La API de su clase es demasiado rígida. Los métodos públicos necesitan más parámetros , o algunos de los métodos privados deben hacerse públicos.

  3. La API de su clase es lo suficientemente flexible, pero debajo de los métodos públicos tiene algunos métodos privados bastante complicados pasando por debajo.

Según su pregunta, podría estar en cualquiera de esos casos.

Para (1), obviamente, primero debe intentar encontrar una forma de probar su método privado con los métodos públicos existentes.

Para (2) y (3), las pruebas unitarias no le dirán en qué caso se encuentra. Lo que necesita hacer es escribir un código de ejemplo. Como Josh Bloch recommends, codifique algunos casos de uso para su API. Su API debe ser el conjunto mínimo de métodos públicos necesarios para satisfacer sus casos de uso.

(3) es el caso donde está bien probar métodos privados. Hay varios tricks for that. Para el código de producción, estos son mejores que exponer su método al usuario API (haciéndolo público) solo para que pueda probarlo. O dividir la funcionalidad relacionada en 2 clases solo para que pueda probarla.

En lugar de pensar en términos de "códigos de olores", que es impreciso y subjetivo, puede pensar en términos de information hiding. Las decisiones de diseño que probablemente cambien no deberían exponerse en su API pública. Preferiblemente, las decisiones de diseño que probablemente cambien no deberían exponerse a las pruebas de su unidad tampoco; es por eso que las personas recomiendan no probar los métodos privados.

Pero si realmente crees que es importante probar tu método privado, y si no puedes hacerlo de manera adecuada a través de los métodos públicos, ¡no sacrifiques la corrección de tu código! Pruebe el método privado. El peor caso es que su código de prueba es más complicado, y debe volver a escribir las pruebas cuando cambie el método privado.

Cuestiones relacionadas