Horario Laboral: De lunes a viernes, de 10AM a 10PM

imagen destacada del post con un texto en el centro que dice Cómo ejecutar tests unitarios y trabajar con contenedores eficientemente y abajo del texto aparece la categoria del post

Introducción

El desarrollo moderno de software demanda procesos sólidos, eficientes y automatizados para garantizar la calidad y estabilidad en cada entrega. Ejecutar tests unitarios es una práctica indispensable para validar que los componentes individuales de una aplicación funcionen correctamente. Sin embargo, el entorno en el que corren estas pruebas puede variar considerablemente, y ahí es donde los contenedores juegan un papel fundamental.

En este artículo técnico y completo, abordaremos cómo aprovechar la potencia de los contenedores, combinada con el manejo inteligente de multi-stage builds en Docker, para ejecutar tests unitarios de manera eficiente, reproducible y escalable. Además, exploraremos el uso de Docker Compose para simplificar y estandarizar estos procesos dentro de un flujo de trabajo DevOps.

¿Por qué ejecutar tests unitarios en contenedores?

Las pruebas unitarias deben ejecutarse en entornos consistentes y controlados. Esto es fundamental para evitar divergencias entre los resultados obtenidos en la máquina del desarrollador y los entornos de integración continua o producción.

Contenerizar el entorno de testing ofrece varias ventajas clave:

  • Consistencia: asegura que las pruebas siempre se ejecuten con las mismas dependencias y configuraciones.
  • Portabilidad: facilita la ejecución de tests en cualquier sistema operativo o infraestructura sin necesidad de instalar herramientas específicas.
  • Escalabilidad y automatización: se integran fácilmente en pipelines de CI/CD para validación automática.

Estructura multi-stage en Docker para compilación y test

Concepto de stages en Dockerfile

El uso de múltiples etapas (multi-stage) en un Dockerfile permite optimizar el proceso de construcción de imágenes. Se crean múltiples fases (stages), cada una con un propósito específico, y luego se selecciona qué artefactos se copian a la siguiente fase o imagen final.

Este patrón es esencial para separar el proceso de compilación, ejecución de tests y generación de la imagen final de la aplicación.

Ejemplo básico: tres stages para build, test y release

Supongamos un proyecto simple en .NET, cuya aplicación retorna un saludo personalizado y tiene associated tests unitarios. Nuestro Dockerfile estará dividido en:

Orquestadores de contenedores en producción para empezar a trabajarOrquestadores de contenedores en producción para empezar a trabajar
  • Stage de Build: usa la imagen oficial del SDK, copia el código fuente y lo compila, generando artefactos binarios.
  • Stage de Test: también usa SDK, copia código fuente y artefactos del stage anterior. Ejecuta los tests unitarios.
  • Stage Final: solo copia los binarios compilados del stage de build. Produce la imagen lista para producción.

Cómo implementar y ejecutar los stages

Dockerfile detallado para etapas

Stage Base Image Acciones Dependencias
Build mcr.microsoft.com/dotnet/sdk Copia código, compila solución Ninguna (inicio)
Test mcr.microsoft.com/dotnet/sdk Copia código y binarios, ejecuta tests Stage Build
Final mcr.microsoft.com/dotnet/aspnet Copia binarios compilados para ejecución Stage Build

Esta separación permite ejecutar cada fase independientemente, optimizando tiempos y recursos.

Construcción e invocación de stages con Docker CLI

Al ejecutar el comando docker build, por defecto se construye y termina en el stage final. Por ejemplo:

docker build -t miapp:latest .

Esto no ejecuta el stage de test, sino solo la compilación y empaquetado final.

Para ejecutar los tests durante la construcción, podemos especificar el stage usando la opción --target:

docker build --target test -t miapp-tests .

Esto fuerza la construcción hasta el stage de tests, ejecutando los tests unitarios dentro del contenedor. Si algún test falla, la construcción falla.

Ventajas de este enfoque en pipelines de CI/CD

  • Control de calidad: la imagen no se construye completamente si hay fallos en los tests.
  • Flexibilidad: permite construir la imagen final sin ejecutar los tests, útil en desarrollos tempranos o despliegues rápidos.
  • Automatización: se puede integrar en scripts y herramientas CI/CD para validar automáticamente cada cambio.

Uso de Docker Compose para simplificar la gestión

Docker Compose facilita la orquestación de múltiples servicios y permite definir en un solo archivo la construcción y ejecución de imágenes y contenedores.

Para el caso de tests unitarios, podemos definir dos servicios en el archivo docker-compose.yml:

Historia y guía completa para empezar a trabajar con contenedoresHistoria y guía completa para empezar a trabajar con contenedores
  • Servicio test: construye utilizando build.target = test y ejecuta los tests unitarios.
  • Servicio aplicación: construye la imagen final sin ejecutar tests, para producción o despliegue.

Ejemplo simplificado de docker-compose.yml

version: '3.8' services: test: build: context: . dockerfile: Dockerfile target: test app: build: context: . dockerfile: Dockerfile 

Para ejecutar los tests, basta con:

docker compose run --rm test

Para ejecutar la aplicación:

docker compose run --rm app

Buenas prácticas y consejos al ejecutar tests unitarios con contenedores

  • Separar Concerns: Mantener los tests y la aplicación en stages separados para optimizar la construcción y el mantenimiento.
  • Validar rápida y frecuentemente: Ejecutar tests en contenedores localmente antes de integrar a la rama principal.
  • Mantener imágenes ligeras: Para el stage final usar bases optimizadas (ej. alpine o runtime específicos) para reducir el tamaño.
  • Logs claros: Configurar outputs y logs legibles para detectar rápidamente errores en tests.
  • Versionado de imágenes: Etiquetar correctamente las imágenes para facilitar rollback o despliegues controlados.

Integración avanzada: test containers y frameworks complementarios

Además de ejecutar tests unitarios dentro de contenedores, existen frameworks como Testcontainers, que permiten levantar contenedores con dependencias externas (bases de datos, colas de mensajes, etc.) de manera dinámica durante la ejecución de tests.

Esto facilita pruebas de integración más realistas y aisladas, mejorando aún más la calidad del software.

Te invitamos a profundizar tus conocimientos prácticos con un recurso audiovisual que ilustra claramente cómo se aplica esta estrategia de stages con Docker para tests unitarios.

Explicación detallada de términos clave

Tests Unitarios

Los tests unitarios son pruebas que verifican el correcto funcionamiento de una unidad mínima de código, normalmente funciones o métodos aislados. Su objetivo principal es detectar errores lógicos y garantizar que los cambios no introduzcan regresiones.

Estos tests deben ser rápidos y ejecutarse sin dependencias externas.

Guía práctica para usar Multi-Stage-Build y trabajar con contenedoresGuía práctica para usar Multi-Stage-Build y trabajar con contenedores

Contenedores

Los contenedores son paquetes estandarizados que encapsulan una aplicación y todas sus dependencias en un entorno aislado. Esto permite ejecutar software con la misma configuración en cualquier entorno, evitando problemas de compatibilidad.

Multi-stage builds

Los multi-stage builds, o construcciones en múltiples etapas, son un mecanismo en Docker para reducir el tamaño final de las imágenes, dividir procesos y reutilizar artefactos entre etapas, mediante diferentes fases dentro de un único Dockerfile.

Docker Compose

Docker Compose es una herramienta para definir y ejecutar aplicaciones Docker multi-contenedor, usando un archivo YAML para configurar servicios, redes y volúmenes, facilitando la gestión y automatización de entornos complejos.

CI/CD

Integración Continua y Despliegue Continuo son prácticas de ingeniería de software que buscan validar y entregar cambios del código base de manera frecuente y automatizada, incluyendo la ejecución automática de tests y despliegues controlados.

Proceso paso a paso para ejecutar tests unitarios en contenedores

  1. Definir stages: crea al menos tres stages en el Dockerfile: build, test y final.
  2. Configurar el stage build: usa una imagen SDK, copia el código fuente y compílalo.
  3. Configurar el stage test: copia binarios y código fuente desde build, y ejecuta los tests con las herramientas disponibles.
  4. Configurar el stage final: basa la imagen en runtime ligero y copia solo los binarios necesarios para producción.
  5. Construir imagen con tests: ejecuta docker build --target test para validar los tests. Esta etapa puede fallar si los tests fallan.
  6. Construir imagen final: ejecuta docker build sin target para construir la imagen de producción.
  7. Usar Docker Compose: define servicios en docker-compose.yml para simplificar ejecución de tests y despliegue.
  8. Integrar en pipelines CI/CD: añade estos pasos para validar y construir imágenes automáticamente.

Comparativa técnica: ejecución de tests con y sin contenedores

Aspecto Tests sin contenedores Tests con contenedores
Consistencia Dependiente del entorno local y config. de cada desarrollador Asegurado por la imagen del contenedor, ambiente fijo
Portabilidad Puede variar entre sistemas operativos Funciona iguales en cualquier máquina con Docker
Aislamiento Posibles interferencias con otros procesos Entorno aislado para evitar conflictos
Integración CI/CD Requiere instalación y configuración previa de dependencias Se integra fácilmente usando imágenes predefinidas
Complejidad Menos pasos en ambientes locales simples Requiere configuración inicial del Dockerfile y Compose

Errores comunes y cómo evitarlos

  • Omisión de dependencias: asegurarse de que el stage test tenga todas las dependencias necesarias para ejecutar.
  • Confusión entre stages: nombrar claramente los stages para evitar errores en referencias.
  • Fallo en tests esperado: interpretar adecuadamente el resultado para decidir si construir la imagen final o no.
  • Imagen final pesada: preferir bases ligeras para evitar despliegues lentos.
  • Logs no visibles: configurar la salida estándar para revisar logs de tests.

Sección de Preguntas Frecuentes (FAQ)

¿Cómo ejecutar pruebas unitarias?

Las pruebas unitarias deben ejecutarse de forma aislada porque tienen que ser rápidas. Todo el conjunto de pruebas unitarias de una aplicación debe ejecutarse en minutos, preferiblemente en segundos. Más adelante se verá por qué. Por eso las pruebas unitarias no pueden utilizar ningún proceso o sistema externo. Ejecutarlas dentro de un contenedor dedicado asegura que corran en un entorno controlado y consistente, evitando interferencias externas y facilitando su integración en procesos automáticos.

¿Qué es un test container?

Test containers es un framework open-source que nos permite desplegar dependencias de infraestructura de nuestra aplicación al lanzar los tests, de manera que podemos probar la aplicación contra la dependencia de infraestructura real. Por ejemplo, se puede desplegar una base de datos temporal en un contenedor al iniciar los tests, garantizando que las pruebas se ejecutan contra un entorno real sin necesidad de instalaciones locales.

¿Cómo puedo integrar la ejecución de tests en mis pipelines CI/CD?

Integrar los tests con contenedores en pipelines es sencillo usando Docker Build con targets y Docker Compose. Primero, configuras el Dockerfile con stages separados para build, test y final. Luego, en el pipeline ejecutas docker build --target test. Si este paso pasa, prosigues con la construcción final. Alternativamente, el uso de Docker Compose permite orquestar estos comandos con mayor simplicidad. Además, puedes programar reglas que detengan el pipeline si los tests fallan, garantizando la calidad.

Containerización para espacios de trabajo: guía práctica para empezarContainerización para espacios de trabajo: guía práctica para empezar

¿Qué hago si los tests fallan al ejecutar el Docker build con –target test?

Si la construcción falla en el stage de tests, significa que alguna prueba unitaria ha salido mal. Es importante revisar los logs de salida para identificar el fallo. La recomendación es corregir los errores en el código, validar localmente los tests y luego volver a hacer el build. Este mecanismo protege el proceso de despliegue automático, evitando que código con errores llegue a producción.

¿Es posible ejecutar tests unitarios sin Docker Compose?

Sí, es posible ejecutar los tests directamente con comandos de Docker CLI usando el target del Dockerfile. Sin embargo, Docker Compose facilita la gestión y estandarización de estos comandos, especialmente en proyectos con múltiples servicios o dependencias, haciendo menos propenso el error humano y más reproducible el proceso.

¿Cómo manejar la configuración de variables y secretos para tests en contenedores?

Las variables de entorno y secretos pueden ser inyectados en los contenedores durante la ejecución mediante Docker Compose o comandos Docker, utilizando archivos .env o directamente con flags como -e. Es fundamental no incluir secretos en las imágenes construidas para mantener seguridad.

¿Se puede usar esta estrategia con otros lenguajes más allá de .NET?

Absolutamente. La estrategia de usar stages para build, test y release es aplicable a cualquier tecnología. Basta utilizar imágenes base adecuadas y adaptar comandos. Por ejemplo, en proyectos de Python o Java, el stage test ejecutará comandos como pytest o mvn test.

¿Qué hacer para minimizar el tamaño de la imagen final tras implementación de tests unitarios?

Lo ideal es usar multi-stage builds con imágenes bases ligeras para la fase final, copiar solo los artefactos esenciales y limpiar caches y archivos temporales dentro del Dockerfile. Este patrón evita cargar herramientas y dependencias de desarrollo en la imagen que se despliega a producción.

Conclusión

Ejecutar tests unitarios dentro de contenedores usando una estrategia basada en stages optimiza la calidad del software y la eficiencia de construcción. Esta metodología garantiza entornos reproducibles, control de versiones confiable y flexibilidad para integrarse en pipelines modernos de CI/CD.

¿Querés mantenerte actualizado con las últimas tendencias en automatización, inteligencia artificial y transformación digital? Visitá nuestro blog de Código6 y descubrí guías, casos de éxito y noticias relevantes para potenciar tu empresa. Ingresá al blog y explorá los recursos más recientes.

Cómo crear dos servidores con Ansible e integrar automatizaciónCómo crear dos servidores con Ansible e integrar automatización
Share

Leave A Comment

Descubre el poder de la IA

Sumérgete en una experiencia transformadora hacia el futuro de la innovación, explorando el potencial ilimitado de la inteligencia artificial en cada interacción.

Impulsa tu empresa con automatización, inteligencia artificial, desarrollo web y SEO técnico. Descubre la transformación digital con Código6.

© 2025 Codigo6 Todos los derechos reservados.