¿Cómo se escriben las pruebas para el código que depende de implementaciones externas concretas que no se pueden burlar?

17

Antecedentes: estoy pensando en intentar presentar el concepto de pruebas unitarias a mis compañeros de trabajo creando algunos para un módulo en el que he estado trabajando; sus requisitos cambiaron recientemente y requieren algunas abstracciones / interacciones más, por lo que parece una buena forma de desarrollar un conjunto de pruebas que "probarán" que funciona sin tener que buscar manualmente la aplicación.

El problema, sin embargo, es que el módulo se basa en factores externos indescifrables, a saber, PDF y XSL. Básicamente leo XML de la base de datos y le aplico una transformación XSL, luego lo convierto a PDF usando una biblioteca llamada ABCPDF. Este PDF se fusiona con otro PDF basado en una plantilla estática. Sé que puedo probar el XML y asegurarme de que los valores son correctos, pero muchos de los posibles errores y problemas están relacionados con la visualización real del documento terminado, por ejemplo, minucias como cuánto tiempo se envuelven las cadenas de texto, donde están ciertas áreas HTML. ubicado en relación con el documento, etc. ¿Es posible probar estas cosas? (Me doy cuenta de que probablemente sean pruebas de integración o ... el tercer tipo de prueba cuyo nombre olvido [no pruebas de aceptación, el otro tipo], y no la unidad pruebas) ya que no puedo, hasta donde sé, simular un PDF fácilmente antes de crearlo y luego volver a leerlo o crear una cadena HTML (es decir, XML transformado) y analizarlo a mano para verificar la presencia de ciertas celdas de tabla en relación con otras celdas de la tabla.

En una situación como esta, ¿debería centrarme en las pruebas unitarias para asegurarme de que la información es correcta y que puedo crear el PDF, o fusionarlos, o lo que sea, y recurrir a las pruebas manuales para los problemas de visualización reales?

Wayne Molina
fuente
66
"factores externos inmovibles" es un indicio de que no está haciendo pruebas unitarias en primer lugar. Eso significa pruebas de integración . Que quieres hacer ¿Pruebas unitarias de su código o pruebas de integración de esta cosa compuesta ? Elija uno u otro, porque es difícil hablar de ambos al mismo tiempo.
S.Lott
2
No estoy comprando "inamovible". Aceptaré "que no sé cómo burlarme", lo que significa que su verdadera pregunta es "¿cómo me burlo?".
Rein Henrichs
Probablemente :) Estoy familiarizado con la burla del XML utilizado, pero no con la manera de burlarse de un documento PDF o HTML real donde importa el formato.
Wayne Molina
1
Creo que te refieres a pruebas "funcionales" (aplicación de extremo a extremo) o "sistema" (múltiples aplicaciones de extremo a extremo)
Gary Rowe
@ Gary - Sí, funcional era la palabra. Ahora los recuerdo de aprender Rails: modelos de pruebas unitarias, controladores de pruebas funcionales, pruebas de integración de todo.
Wayne Molina

Respuestas:

13

Pruebe la función, no la unidad

Usando entradas xml conocidas, imprima un PDF y verifique manualmente (y meticulosamente) que sea correcto. Luego guárdelo como referencia.

Las pruebas futuras que usen las mismas entradas xml pueden hacer una comparación de archivos binarios con la referencia.

Si una comparación a nivel de archivo no es satisfactoria, muestre el PDF al final de la prueba y tome capturas de pantalla, luego haga que la prueba automatizada se compare con las capturas de pantalla de referencia.

Steven A. Lowe
fuente
+1 porque solo te interesa el resultado final en este nivel. Si cambia la implementación de cómo llega a obtener el PDF, no debería tener que cambiar su prueba funcional.
Gary Rowe
2
+1 para buenos consejos, esto es lo que hacemos en nuestro proyecto actual. Creamos un conjunto de herramientas personalizadas para hacer la comparación de PDF, lo que nos permite omitir partes cambiantes en los documentos, como las marcas de tiempo. Advertencia: cambiar a un procesador de PDF diferente (versión del) puede causar cambios sutiles en el diseño, lo que provoca una comparación binaria directa para señalar montones de falsos positivos.
Péter Török
5

Normalmente, en un caso como este, abstrae todo lo que no puede probar detrás de una implementación que puede usar con una interfaz. Simplemente haré algo tonto como el generador de PDF porque eso parece razonable.

public class PdfBuilder : IPdfBuilder
{
  public byte[] BuildPdf(...)
  {
    // actual untestable code here
  }
}

public interface IPdfBuilder
{
  byte[] BuildPdf(...);
}

Luego puede burlarse del IPdfBuilder en sus pruebas para hacer lo que quiera. Esto a menudo significa que debe comenzar a usar un contenedor de IoC ( /programming/871405/why-do-i-need-an-ioc-container-as-opposed-to-straightforward-di-code y /programming/21288/which-net-dependency-injection-frameworks-are-worth-looking-into como lugar para comenzar) si no está usando uno ahora.

Y las pruebas que no son pruebas unitarias a menudo se llaman pruebas de integración. Las pruebas de integración complicadas a menudo no valen la pena, por lo que simplemente abstrae esa parte y reduce la cantidad de lógica de negocios en esa abstracción para que pueda probarla en una prueba unitaria.

Avísame si esto no está totalmente claro.

Travis
fuente
+1 por ocultar código no comprobable. Luego puede hacer pruebas manuales hasta que descubra qué necesita cruzar esa interfaz para obtener el resultado correcto, y una prueba unitaria para que se genere correctamente para obtener sus pruebas unitarias de regresión.
Ethel Evans
1

Construí algo muy similar hace un tiempo, y solo usé pruebas visuales básicas. Las pruebas no tienen que ser automatizadas, por lo que no hay nada de malo en buscar un resultado esperado (obviamente, en una variedad de situaciones predeterminadas). A menudo, una imagen vale más que mil pruebas en lo que respecta a las imágenes . Uso pruebas unitarias automatizadas ampliamente, pero creo que algunas personas pueden dejarse llevar un poco cuando entran en las pruebas de GUI, o cualquier cosa visual en mi humilde opinión. Con cierto producto, reconozco que este enfoque "suficientemente bueno" no será suficiente para YMMV.

Sin embargo, estaría un poco preocupado por las externalidades inamovibles. Esto puede ser un signo de acoplamiento estrecho, lo cual es bueno evitar como regla general, pero no especularé demasiado sobre su código a ese respecto sin más detalles.

Morgan Herlocker
fuente
Está muy estrechamente acoplado, pero esa es un área que no puedo solucionar, ya que no hay una aceptación para hacerlo libremente y no se dedican recursos a la refactorización (pero ese es un conjunto completamente diferente de problemas).
Wayne Molina