Evaluar si escribir pruebas unitarias o pruebas de integración primero en proyectos de prototipos / cielo azul

11

Algo que noté recientemente es cuando estoy haciendo los siguientes tipos de proyectos:

  • Al comenzar un proyecto
  • Trabajando en un MVP / prototipo
  • Agregar características que no están completamente definidas
  • Trabajando en un proyecto de menor escala

Como referencia, ahora estoy trabajando en un proyecto de Python que actualmente tiene ~ 1k líneas de código, incluidos algunos comentarios y todos los espacios en blanco.

Me resulta inmensamente más fácil escribir primero las pruebas de integración, trabajar en el código y luego, una vez que la API se endurece, realmente funciona para agregar pruebas unitarias. Los tipos de pruebas que puedo ejecutar en mi mainfunción, por así decirlo, son más "de principio a fin" que cualquier otra cosa.

Esto se debe a que las pruebas unitarias son realmente molestas cuando una API está cambiando con bastante rapidez, que a menudo es el caso cuando se trabaja en un proyecto que coincide con alguno o la mayoría de los criterios anteriores.

¿Es este enfoque un buen enfoque y qué criterios deben considerarse al tomar la decisión de comenzar primero con pruebas unitarias o de integración para este tipo de proyectos? ¿Me falta el valor de las pruebas unitarias de este tipo de proyectos antes de que las API se solidifiquen más?

Enderland
fuente
66
Haz lo que sea mejor para ti. No escuches a las personas que dicen que debes trabajar de cierta manera para ser eficiente: sabes cuándo eres eficiente y cuándo no. Si usted escribe primero las pruebas de integración, o las pruebas unitarias primero, realmente no importa. Para algunos proyectos, una forma puede ser más fácil, y para otros, la otra. Lo que está describiendo puede ser la diferencia entre el diseño de arriba hacia abajo y de abajo hacia arriba. Ambos son útiles, pero de arriba hacia abajo generalmente producen mejores diseños.
Frank Hileman el
@FrankHileman, ese es mi enfoque. Pero como tengo curiosidad, quiero asegurarme de que estoy haciendo el enfoque correcto en caso de que me falte algo.
enderland
Enfóquese primero en las especificaciones: las porciones sin código. ¿Cuáles son los invariantes del sistema? Al hacer esto, es posible que necesite descubrir primero el nivel bajo o el nivel alto primero. Depende de dónde se encuentren los algoritmos más críticos o riesgosos. Trate de quitarlos del camino primero. Esa es la gestión básica de riesgos.
Frank Hileman
1
En caso de trabajar en un prototipo, está bien no escribir pruebas en absoluto. El objetivo del prototipo es verificar la idea de trabajo. La implementación del prototipo ayudará a reconocer el diseño esperado de la aplicación.
Fabio
Se llama desarrollo de afuera hacia adentro. Es posible que desee consultar el siguiente libro, que hace exactamente eso: amazon.com/dp/0321503627
Eternal21

Respuestas:

7

¿Me falta el valor de las pruebas unitarias de este tipo de proyectos antes de que las API se solidifiquen más?

No. Lo estás haciendo bien.

Los dos grandes objetivos de TDD son:

  • Definición de interfaces por uso real, en lugar de por implementación interna 1
  • Maximizando la cobertura de prueba

La cobertura de prueba se puede maximizar bastante bien en cualquier dirección. Es decir, independientemente de si primero prueba unidades pequeñas , aisladas o grandes , unidades "integradas", tiene la opción de escribir sus pruebas antes de sus implementaciones.

Lo que gana al escribir pruebas de nivel superior ("integración") primero, como lo está haciendo, es la seguridad de que sus interfaces e interacciones de nivel superior también se definen principalmente de acuerdo con su uso, en lugar de sus implementaciones internas.

El mismo efecto se puede lograr en gran medida con una buena "arquitectura" y diagramación. Pero, esas pruebas de alto nivel a menudo pueden revelar cosas que omitió en sus diagramas, o que simplemente se equivocó en su trabajo de "arquitectura".


Si no estás haciendo TDD (o algo similar), el orden en que escribes las pruebas no importa mucho. Las interfaces ya existen en el momento de la prueba, por lo que es mucho menos probable que sus pruebas cambien algo; solo servirán para proteger contra cambios de ruptura particulares.

Pero, si le preocupa construir la implementación de arriba hacia abajo frente a abajo, el primer punto todavía se aplica en gran medida. El código de alto nivel ayuda a definir interfaces de bajo nivel. Mientras que, si las interfaces de bajo nivel se escriben primero (o ya existen), el código de alto nivel está a su merced ...


1. Este también se aplica incluso si no está haciendo TDD completo. Incluso si solo está escribiendo 1 o 2 pruebas antes de su implementación, esas 1 o 2 pruebas pueden ayudarlo a definir o refinar sus interfaces antes de que sea demasiado tarde.

svidgen
fuente
1

He trabajado como tú trabajas. Y no voy a decirte que no puedes. Te advertiré sobre algo con lo que te puedas encontrar.

Cuando cada prueba unitaria es simplemente una modificación, es difícil aprender a hacerlas flexibles. Tienden a ser nada más que pruebas de regresión. Como nunca los ha usado para ayudarlo a refactorizar, es muy fácil escribir los tipos de pruebas que realmente hacen que la refactorización sea más difícil. Esto tiende a salirse de control hasta que pierdes toda la fe en TDD.

Sin embargo, ya estás trabajando en algo. No te voy a decir que pares. Diré que valdría la pena comenzar algo más que tenga tiempo para explorar y seguir el ciclo de refactorización rojo verde desde el principio. Asegúrese de utilizar las pruebas para ayudarlo a refactorizar. Hasta que hayas dominado esta forma de trabajo, úsala con moderación en algo importante. Esta es una forma muy diferente de codificar y lleva tiempo acostumbrarse. Hacerlo a la mitad no le hará ningún bien a nadie.

Que dicho

Me resulta inmensamente más fácil escribir primero las pruebas de integración, trabajar en el código y luego, una vez que la API se endurece, realmente funciona para agregar pruebas unitarias. Los tipos de pruebas que puedo ejecutar en mi función principal, por así decirlo, son más "de principio a fin" que cualquier otra cosa.

Comprenda que una prueba unitaria NO es simplemente una prueba que actúa en una clase. Siempre que la API en la que esté trabajando pueda probarse sin hacer nada de lo siguiente, está haciendo pruebas unitarias muy bien:

  • Habla a la base de datos
  • Se comunica a través de la red.
  • Toca el sistema de archivos
  • No puede ejecutarse al mismo tiempo que cualquiera de sus otras pruebas unitarias
  • Tienes que hacer cosas especiales en tu entorno (como editar archivos de configuración) para ejecutarlo.

Michael Feathers: un conjunto de reglas de prueba de unidad

Entonces, si su prueba de punta a punta involucra más de un objeto, está bien. Esta es una prueba unitaria, no una prueba de objeto.

Al igual que los métodos privados ya no necesitan ser probados luego de ser probados mediante la prueba de los métodos públicos que los usan, los objetos no necesitan ser desarrollados inicialmente bajo su propio arnés de prueba. Solo cuando se considera que los objetos se usan independientemente de la historia de extremo a extremo, realmente necesitan ser tratados como si tuvieran su propia interfaz y comportamiento para confirmar. Si tienes cuidado al respecto, es cuando haces públicos esos objetos. De esta manera no haces promesas que no hayas probado.

naranja confitada
fuente