Unidad de prueba de componentes internos


14

¿Hasta qué punto prueba los componentes internos / privados de una clase / módulo / paquete / etc.? ¿Los prueba en absoluto o simplemente prueba la interfaz con el mundo exterior? Un ejemplo de estos métodos internos es privado.

Como ejemplo, imagine un analizador de descenso recursivo , que tiene varios procedimientos internos (funciones / métodos) llamados desde un procedimiento central. La única interfaz con el mundo exterior es el procedimiento central, que toma una cadena y devuelve la información analizada. Los otros procedimientos analizan diferentes partes de la cadena, y se llaman desde el procedimiento central u otros procedimientos.

Naturalmente, debe probar la interfaz externa llamándola con cadenas de muestra y comparándola con la salida analizada a mano. ¿Pero qué hay de los otros procedimientos? ¿Los probaría individualmente para verificar que analizan sus subcadenas correctamente?

Puedo pensar en algunos argumentos:

Pros :

  1. Más pruebas siempre es mejor, y esto puede ayudar a aumentar la cobertura del código
  2. Algunos componentes internos pueden ser difíciles de dar entradas específicas (casos extremos, por ejemplo) al dar entrada a la interfaz externa
  3. Pruebas más claras. Si un componente interno tiene un error (fijo), un caso de prueba para ese componente deja en claro que el error estaba en ese componente específico

Contras :

  1. La refactorización se vuelve demasiado dolorosa y lleva mucho tiempo. Para cambiar cualquier cosa, debe volver a escribir las pruebas unitarias, incluso si los usuarios de la interfaz externa no se ven afectados
  2. Algunos lenguajes y marcos de prueba no lo permiten

Cuales son tus opiniones


posible duplicado o superposición significativa con: programmers.stackexchange.com/questions/10832/…
azheglov

Respuestas:


8

Caso: un "módulo" (en un sentido amplio, es decir, algo que tiene una interfaz pública y posiblemente también algunas partes internas privadas) tiene una lógica complicada / involucrada dentro de él. Probar solo la interfaz del módulo será una especie de prueba de integración con relación a la estructura interna del módulo y, por lo tanto, en caso de que se encuentre un error, dicha prueba no localizará la parte / componente interno exacto responsable de la falla.

Solución: convierta las partes internas complicadas en módulos, pruébelos en unidad (y repita estos pasos si son demasiado complicados) e impórtelos en su módulo original. Ahora tiene solo un conjunto de módulos lo suficientemente simples como para unificar pruebas (ambos verifican que el comportamiento sea correcto y corrigen errores) fácilmente, y eso es todo.

Nota:

  • no habrá necesidad de cambiar nada en las pruebas de los "submódulos" (anteriores) del módulo al cambiar el contrato del módulo, a menos que el "submódulo" ya no ofrezca servicios suficientes para cumplir con el contrato nuevo / modificado.

  • no se hará público innecesariamente, es decir, se mantendrá el contrato del módulo y se mantendrá la encapsulación.

[Actualizar]

Para probar alguna lógica interna inteligente en los casos en que es difícil poner las partes internas del objeto (me refiero a los miembros, no a los módulos / paquetes importados de forma privada) en el estado apropiado con solo alimentar las entradas a través de la interfaz pública del objeto:

  • solo tenga un código de prueba con acceso amigo (en términos de C ++) o paquete (Java) a las entrañas, configurando el estado desde adentro y probando el comportamiento como desee.

    • esto no interrumpirá la encapsulación nuevamente al tiempo que proporciona un acceso directo y fácil a las partes internas para fines de prueba: simplemente ejecute las pruebas como un "recuadro negro" y compílelas en las versiones de lanzamiento.

y el diseño de la lista parece estar un poco roto; (
mlvljr

1
Buena respuesta. En .NET puede usar el [assembly: InternalsVisibleTo("MyUnitTestAssembly")]atributo en su AssemblyInfo.cspara probar elementos internos. Sin embargo, se siente como hacer trampa.
Nadie el

@rmx Una vez que algo satisface todos los criterios necesarios, no es trampa, incluso si tiene algo en común con las trampas reales. Pero el tema del acceso inter / intramódulo es realmente un poco inventado en los idiomas principales modernos.
mlvljr

2

El enfoque del código basado en FSM es un poco diferente del utilizado tradicionalmente. Es muy similar a lo que se describe aquí para las pruebas de hardware (que generalmente también es un FSM).

En resumen, usted crea una secuencia de entrada de prueba (o un conjunto de secuencias de entrada de prueba) que no solo debe producir una salida determinada, sino que también cuando produce una salida "mala" particular permite identificar el componente fallado por la naturaleza de la falla. El enfoque es bastante escalable, cuanto más tiempo pase en el diseño de la prueba, mejor será la prueba.

Este tipo de prueba está más cerca de lo que se llama "pruebas funcionales", pero elimina la necesidad de cambiar las pruebas cada vez que toca ligeramente una implementación.


2

Bueno, eso depende :-). Si está siguiendo un enfoque BDD (Behavior Driven Development) o ATDD (Acceptance Test Driven Development), entonces probar la interfaz pública está bien (siempre que lo pruebe exhaustivamente con diferentes entradas. La implementación subyacente, por ejemplo, métodos privados no es realmente importante

Sin embargo, digamos que desea que parte de ese algoritmo se ejecute dentro de un cierto período de tiempo o a lo largo de una cierta curva bigO (por ejemplo, nlogn), entonces sí, probar las partes individuales es importante. Algunos lo llamarían más un enfoque tradicional de TDD / Prueba de Unidad.

Como con todo, YMMV


1

Dividirlo en varias partes con un sentido funcional, por ejemplo ParseQuotedString(), ParseExpression(), ParseStatement(), ParseFile()y hacer que todo el público. ¿Qué tan probable es que su sintaxis cambie tanto que estos se vuelvan irrelevantes?


1
Este enfoque conduce fácilmente a una encapsulación más débil y a interfaces más grandes y difíciles de usar / comprender.
Sara
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.