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:

- 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
:

- 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.

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
- Definir stages: crea al menos tres stages en el Dockerfile: build, test y final.
- Configurar el stage build: usa una imagen SDK, copia el código fuente y compílalo.
- Configurar el stage test: copia binarios y código fuente desde build, y ejecuta los tests con las herramientas disponibles.
- Configurar el stage final: basa la imagen en runtime ligero y copia solo los binarios necesarios para producción.
- Construir imagen con tests: ejecuta
docker build --target test
para validar los tests. Esta etapa puede fallar si los tests fallan. - Construir imagen final: ejecuta
docker build
sin target para construir la imagen de producción. - Usar Docker Compose: define servicios en docker-compose.yml para simplificar ejecución de tests y despliegue.
- 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.

¿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.

Leave A Comment