window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versión: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster ya existe') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Contenedores de pruebas - ¿Cómo facilitar las pruebas? - The Codest
The Codest
  • Quiénes somos
  • Servicios
    • Desarrollo de software
      • Desarrollo Frontend
      • Desarrollo backend
    • Staff Augmentation
      • Desarrolladores frontales
      • Desarrolladores de backend
      • Ingenieros de datos
      • Ingenieros de la nube
      • Ingenieros de control de calidad
      • Otros
    • Asesoramiento
      • Auditoría y consultoría
  • Industrias
    • Fintech y Banca
    • E-commerce
    • Adtech
    • Tecnología sanitaria
    • Fabricación
    • Logística
    • Automoción
    • IOT
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • Nuestro equipo
  • Case Studies
  • Saber cómo
    • Blog
    • Meetups
    • Seminarios en línea
    • Recursos
Carreras profesionales Póngase en contacto
  • Quiénes somos
  • Servicios
    • Desarrollo de software
      • Desarrollo Frontend
      • Desarrollo backend
    • Staff Augmentation
      • Desarrolladores frontales
      • Desarrolladores de backend
      • Ingenieros de datos
      • Ingenieros de la nube
      • Ingenieros de control de calidad
      • Otros
    • Asesoramiento
      • Auditoría y consultoría
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • Nuestro equipo
  • Case Studies
  • Saber cómo
    • Blog
    • Meetups
    • Seminarios en línea
    • Recursos
Carreras profesionales Póngase en contacto
Flecha atrás VOLVER
2022-07-26
Desarrollo de software

Contenedores de pruebas - ¿Cómo facilitar las pruebas?

Bartlomiej Kuczynski

¿Buscas una manera de hacer tests de forma más sencilla? ¡Te hemos pillado! Consulta el siguiente artículo y aprende cómo hacerlo posible.

El desarrollo moderno de aplicaciones se basa en una regla muy sencilla:

Utilizar la composición

Componemos clases, funciones y servicios en piezas de software más grandes. Ese último elemento es la base de los microservicios y arquitectura hexagonal. Nos gustaría utilizar las soluciones existentes, integrarlas con nuestro software y pasar directamente a la mercado.

¿Quiere gestionar el registro de cuentas y almacenar los datos de los usuarios? Puede elegir uno de los servicios OAuth. ¿Tal vez tu aplicación ofrece algún tipo de suscripción o pago? Hay muchos servicios que pueden ayudarle a manejar esto. ¿Necesita algún tipo de análisis en su sitio web, pero no entiende GDPR? Siéntase libre y tome una de las soluciones listas para usar.

Algo que facilita tanto el desarrollo desde el punto de vista empresarial podría darle un dolor de cabeza: el momento en que necesita escribir una simple prueba.

Las bestias fantásticas: Colas, bases de datos y cómo probarlas

Las pruebas unitarias son bastante sencillas. Si sólo sigues las reglas, entonces tu entorno de pruebas y código son saludables. ¿Qué normas son ésas?

  • Fácil de escribir - una prueba unitaria debe ser fácil de escribir porque se escriben muchas. Menos esfuerzo significa que se escriben más pruebas.
  • Legible - el código de la prueba debe ser fácil de leer. La prueba es una historia. Describe el comportamiento del software y puede utilizarse como un atajo de documentación. Una buena prueba unitaria ayuda a corregir errores sin depurar el código.
  • Fiable - la prueba debe fallar sólo si hay un error en el sistema que se está probando. ¿Es obvio? No siempre. A veces las pruebas pasan si las ejecutas una a una, pero fallan cuando las ejecutas en conjunto. Pasan en tu máquina, pero fallan en CI (Funciona en mi máquina). Una buena prueba unitaria sólo tiene una razón para fallar.
  • Rápido - Las pruebas deben ser rápidas. La preparación para la ejecución, el inicio y la propia ejecución de las pruebas deben ser muy rápidos. De lo contrario, las escribirá, pero no las ejecutará. Las pruebas lentas significan pérdida de concentración. Esperas y miras la barra de progreso.
  • Independiente - por último, la prueba debe ser independiente. Esta regla se deriva de las anteriores. Sólo las pruebas verdaderamente independientes pueden constituir una unidad. No interfieren entre sí, pueden ejecutarse en cualquier orden y los posibles fallos no dependen de los resultados de otras pruebas. Independiente también significa que no depende de ningún recurso externo, como bases de datos, servicios de mensajería o sistemas de archivos. Si necesitas comunicarte con recursos externos, puedes utilizar mocks, stubs o dummies.

Todo se complica cuando queremos escribir algunas pruebas de integración. No está mal si queremos probar unos cuantos servicios juntos. Pero cuando necesitamos probar servicios que utilizan recursos externos como bases de datos o servicios de mensajería, entonces nos estamos buscando problemas.

Para ejecutar la prueba, debe instalar...

Hace muchos años, cuando queríamos hacer algunas pruebas de integración y utilizar, por ejemplo, bases de datos, teníamos dos opciones:

  1. Podemos instalar una base de datos localmente. Configura un esquema y conéctate desde nuestra prueba;
  2. Podemos conectarnos a una instancia existente "en algún lugar del espacio".

Ambas tienen pros y contras. Pero ambas introducen niveles adicionales de complejidad. A veces se trataba de complejidad técnica derivada de las características de determinadas herramientas, por ejemplo, la instalación y gestión de la base de datos Oracle en el host local. A veces era un inconveniente en el proceso, por ejemplo, tienes que ponerte de acuerdo con la prueba equipo sobre el uso de JMS... cada vez que quiera ejecutar pruebas.

Contenedores al rescate

En los últimos 10 años, la idea de la contenedorización ha ganado reconocimiento en la industria. Por lo tanto, una decisión natural es elegir los contenedores como solución para nuestro problema de pruebas de integración. Se trata de una solución sencilla y limpia. Basta con ejecutar la compilación del proceso y ¡todo funciona! ¿No te lo puedes creer? Echa un vistazo a esta sencilla configuración de una construcción maven:

com.dkanejs.maven.plugins
     docker-compose-maven-plugin
     4.0.0
     
       
         up
         prueba-compilación
         
           arriba
         
         
           ${proyecto.basedir}/docker-compose.yml
           true
         
       
       
         abajo
         posterior a la prueba de integración
         
           down
         
         
           ${project.basedir}/docker-compose.yml
           true

Y el docker-compose.yml Además, el expediente tiene muy buena pinta.

versión: "3.5"

servicios:

 postgres:
   nombre_contenedor: reactivedb
   imagen: postgres:13.2
   reiniciar: siempre
   entorno:
     - POSTGRES_USER=admin
     - POSTGRES_PASSWORD=contraseña
     - POSTGRES_DB=ciudades
   puertos:
     - "5432:5432"
   volúmenes:
     - postgres_data:/data/db

 pgadmin
   nombre_contenedor: pgadmin4
   imagen: dpage/pgadmin4
   reinicio: siempre
   entorno:
     PGADMIN_DEFAULT_EMAIL: [email protected]
     PGADMIN_DEFAULT_PASSWORD: contraseña
   puertos:
     - "15050:80"
   volúmenes:
     - pgadmin_data:/data/pgadmin

volúmenes:
 postgres_data:
 pgadmin_data:

Pero, ¿se da cuenta del problema?

Un carguero que lo bloquea todo

El ejemplo anterior es muy simple. Sólo una base de datos postgres, pgAdmin y eso es todo. Cuando ejecutes

bash
$ mvn clean verify

entonces el plugin de maven inicia los contenedores y después de las pruebas los apaga. Los problemas empiezan cuando el proyecto crece y nuestro fichero de composición crece también. Cada vez tendrás que arrancar todos los contenedores, y estarán vivos durante toda la compilación. Puedes mejorar un poco la situación cambiando la configuración de ejecución del plugin, pero no es suficiente. En el peor de los casos, ¡tus contenedores agotarán los recursos del sistema antes de que comiencen las pruebas!

Y este no es el único problema. No puedes ejecutar una sola prueba de integración desde tu IDE. Antes de eso, necesitas arrancar los contenedores a mano. Además, la siguiente ejecución de maven derribará esos contenedores (echa un vistazo a abajo ejecución).

Así que esta solución es como un gran carguero. Si todo funciona bien, no pasa nada. Cualquier comportamiento inesperado o poco común nos lleva a algún tipo de desastre.

Contenedores de prueba: ejecute contenedores desde las pruebas

Pero, ¿y si pudiéramos ejecutar nuestros contenedores desde las pruebas? Esta idea parece buena, y ya se está poniendo en práctica. Contenedores de pruebaya que estamos hablando de este proyecto, he aquí una solución para nuestros problemas. No es ideal, pero nadie es perfecto.

Se trata de un Java que soporta pruebas JUnit y Spock, proporcionando formas ligeras y fáciles de ejecutar el contenedor Docker. ¡Echémosle un vistazo y escribamos algo de código!

Requisitos previos y configuración

Antes de empezar, tenemos que comprobar nuestra configuración. Contenedores de prueba necesidad:

  • Docker en la versión v17.09,
  • Java versión mínima 1.8,
  • Acceso a la red, especialmente a docker.hub.

Encontrará más información sobre los requisitos para sistemas operativos y CI específicos en
en documentación.

Ahora es el momento de añadir algunas líneas a pom.xml.

Utilizo spring boot en el proyecto para reducir boilerplate. Contenedores de prueba son independientes de Spring Framework y se pueden utilizar sin él.
org.testcontainers
       testcontainers-bom
       ${testcontaines.version}
       pom
       importar
     
   
 
 
   
     org.postgresql
     postgresql
     runtime
   
   
     org.testcontainers
     postgresql
     prueba
   
   
     org.testcontainers
     junit-jupiter
     prueba

Utilizo Contenedores de prueba versión 1.17.3pero siéntase libre de utilizar el más reciente.

Pruebas con el contenedor Postgres

El primer paso es preparar nuestra instancia de un contenedor. Puedes hacerlo directamente en la prueba, pero una clase independiente queda mejor.

public class Postgres13TC extends PostgreSQLContainer {

 private static final Postgres13TC TC = new Postgres13TC();

 private Postgres13TC() {
   super("postgres:13.2");
 }

 public static Postgres13TC getInstance() {
   return TC;
 }

 @Override
 public void start() {
   super.start();
   System.setProperty("DB_URL", TC.getJdbcUrl());
   System.setProperty("DB_USERNAME", TC.getUsername());
   System.setProperty("DB_PASSWORD", TC.getPassword());
 }

 @Override
 public void stop() {
   // no hace nada. Esta es una instancia compartida. Deja que la JVM se encargue de esta operación.
 }
}

Al principio de las pruebas, crearemos una instancia de Postgres13TC. Esta clase puede manejar información sobre nuestro contenedor. Lo más importante aquí son las cadenas de conexión a la base de datos y las credenciales. Ahora es el momento de escribir una prueba muy simple.

@Contenedoresdepruebas
clase SimpleDbTest {

 @Contenedor
 private static Postgres13TC = Postgres13TC.getInstance();

 @Prueba
 void testConnection() {
   assumeThat(postgres13TC.isRunning());
   var connectionProps = new Properties();
   connectionProps.put("usuario", postgres13TC.getUsername());
   connectionProps.put("contraseña", postgres13TC.getPassword());

   try (Connection = DriverManager.getConnection(postgres13TC.getJdbcUrl(),
       connectionProps)) {
     var resultSet = connection.prepareStatement("Select 1").executeQuery();
     resultSet.next();
     assertThat(resultSet.getInt(1)).isEqualTo(1);
   } catch (SQLException sqlException) {
     assertThat((Exception) sqlException).doesNotThrowAnyException();
   }
 }
}

Aquí utilizo JUnit 5. Anotación @Testcontainers forma parte de las extensiones que controlan los contenedores en el entorno de prueba. Encuentran todos los campos con @Contenedor y los contenedores de inicio y parada, respectivamente.

Pruebas con Spring Boot

Como he mencionado antes, utilizo Spring Boot en el proyecto. En este caso, tenemos que escribir un poco más de código. El primer paso es crear una clase de configuración adicional.

@Slf4j
public class ContainerInit implements
   ApplicationContextInitializer {

 public static Postgres13TC;

 static {
   postgres13TC = Postgres13TC.getInstance();
   postgres13TC.start();
 }

 @Override
 public void initialize(ConfigurableApplicationContext applicationContext) {
   TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
       applicationContext,
       "spring.datasource.url=" + postgres13TC.getJdbcUrl(),
       "spring.datasource.username=" + postgres13TC.getUsername(),
       "spring.datasource.password=" + postgres13TC.getPassword(),
       "db.host=" + postgres13TC.getHost(),
       "db.port=" + postgres13TC.getMappedPort(postgres13TC.POSTGRESQL_PORT),
       "db.name=" + postgres13TC.getDatabaseName(),
       "db.username=" + postgres13TC.getUsername(),
       "db.password=" + postgres13TC.getPassword()
   );
 }
}

Esta clase sustituye las propiedades existentes con valores de la clase contenedor de prueba. Las tres primeras propiedades son propiedades estándar de Spring. Las cinco siguientes son propiedades adicionales personalizadas que se pueden utilizar para configurar otros recursos y extensiones como liquibase, por ejemplo:

spring.liquibase.change-log=classpath:/db/changelog/dbchangelog.xml
spring.liquibase.url=jdbc:postgresql://${db.host:localhost}:${db.port:5432}/${db.name:cities}
spring.liquibase.user=${db.username:admin}
spring.liquibase.password=${db.password:password}
spring.liquibase.enabled=true

Ahora es el momento de definir una prueba de integración sencilla.

@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureTestDatabase(replace = NONE)
@ContextConfiguration(inicializadores = ContainerInit.class)
@ContenedoresDePrueba
clase DummyRepositoryTest {

 @Autocableado
 privado DummyRepository;

 @Prueba
 void shouldReturnDummy() {
   var byId = dummyRepository.getById(10L);
   var expected = new Dummy();
   expected.setId(10L);
   assertThat(byId).completes().emitsCount(1).emits(expected);
 }
}

Aquí tenemos algunas anotaciones adicionales.

  • @SpringBootTest(webEnvironment = RANDOM_PORT) - marca la prueba como una prueba de Spring Boot e inicia el contexto de Spring.
  • @AutoConfigureTestDatabase(replace = NONE) - estas anotaciones dicen que la extensión de prueba de spring no debe reemplazar la configuración de la base de datos postgres con H2 en la configuración de memoria.
  • @ContextConfiguration(inicializadores = ContainerInit.class) - un contexto primaveral adicional
    donde establecemos las propiedades de Contenedores de prueba.
  • @Testcontainers - como se ha mencionado anteriormente, esta anotación controla el ciclo de vida del contenedor.

En este ejemplo, utilizo repositorios reactivos, pero funciona igual con repositorios JDBC y JPA comunes.

Ahora podemos ejecutar esta prueba. Si es la primera vez que se ejecuta, el motor necesita extraer imágenes de docker.hub. Esto puede tardar un momento. Después de eso, veremos que dos contenedores se han ejecutado. Uno es postgres y el otro es el controlador Testcontainers. Ese segundo contenedor gestiona los contenedores en ejecución e incluso si la JVM se detiene inesperadamente, entonces apaga los contenedores y limpia el entorno.

Resumamos

Contenedores de prueba son herramientas muy fáciles de usar que nos ayudan a crear pruebas de integración que utilizan contenedores Docker. Eso nos da más flexibilidad y aumenta la velocidad de desarrollo. La configuración adecuada de las pruebas reduce el tiempo necesario para embarcar a los nuevos desarrolladores. No necesitan configurar todas las dependencias, solo ejecutar las pruebas escritas con los archivos de configuración seleccionados.

bandera de cooperación

Artículos relacionados

Desarrollo de software

Crear aplicaciones web preparadas para el futuro: ideas del equipo de expertos de The Codest

Descubra cómo The Codest destaca en la creación de aplicaciones web escalables e interactivas con tecnologías de vanguardia, ofreciendo experiencias de usuario fluidas en todas las plataformas. Descubra cómo nuestra experiencia impulsa la transformación...

EL MEJOR
Desarrollo de software

Las 10 mejores empresas de desarrollo de software de Letonia

Conozca las principales empresas de desarrollo de software de Letonia y sus innovadoras soluciones en nuestro último artículo. Descubra cómo estos líderes tecnológicos pueden ayudarle a mejorar su negocio.

thecodest
Soluciones para empresas y escalas

Fundamentos del desarrollo de software Java: Guía para externalizar con éxito

Explore esta guía esencial sobre el desarrollo de software Java outsourcing con éxito para mejorar la eficiencia, acceder a la experiencia e impulsar el éxito de los proyectos con The Codest.

thecodest
Desarrollo de software

La guía definitiva para subcontratar en Polonia

El auge de las outsourcing en Polonia está impulsado por los avances económicos, educativos y tecnológicos, que fomentan el crecimiento de las TI y un clima favorable a las empresas.

TheCodest
Soluciones para empresas y escalas

Guía completa de herramientas y técnicas de auditoría informática

Las auditorías informáticas garantizan sistemas seguros, eficientes y conformes. Obtenga más información sobre su importancia leyendo el artículo completo.

The Codest
Jakub Jakubowicz CTO y Cofundador

Suscríbase a nuestra base de conocimientos y manténgase al día de la experiencia del sector informático.

    Quiénes somos

    The Codest - Empresa internacional de desarrollo de software con centros tecnológicos en Polonia.

    Reino Unido - Sede central

    • Oficina 303B, 182-184 High Street North E6 2JA
      Londres, Inglaterra

    Polonia - Centros tecnológicos locales

    • Parque de oficinas Fabryczna, Aleja
      Pokoju 18, 31-564 Cracovia
    • Embajada del Cerebro, Konstruktorska
      11, 02-673 Varsovia, Polonia

      The Codest

    • Inicio
    • Quiénes somos
    • Servicios
    • Case Studies
    • Saber cómo
    • Carreras profesionales
    • Diccionario

      Servicios

    • Asesoramiento
    • Desarrollo de software
    • Desarrollo backend
    • Desarrollo Frontend
    • Staff Augmentation
    • Desarrolladores de backend
    • Ingenieros de la nube
    • Ingenieros de datos
    • Otros
    • Ingenieros de control de calidad

      Recursos

    • Hechos y mitos sobre la cooperación con un socio externo de desarrollo de software
    • De EE.UU. a Europa: ¿Por qué las startups estadounidenses deciden trasladarse a Europa?
    • Comparación de los polos de desarrollo de Tech Offshore: Tech Offshore Europa (Polonia), ASEAN (Filipinas), Eurasia (Turquía)
    • ¿Cuáles son los principales retos de los CTO y los CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Condiciones de uso del sitio web

    Copyright © 2025 por The Codest. Todos los derechos reservados.

    es_ESSpanish
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean nl_NLDutch etEstonian elGreek es_ESSpanish