The Codest
  • Sobre nós
  • Serviços
    • Desenvolvimento de software
      • Desenvolvimento de front-end
      • Desenvolvimento backend
    • Staff Augmentation
      • Programadores Frontend
      • Programadores de back-end
      • Engenheiros de dados
      • Engenheiros de nuvem
      • Engenheiros de GQ
      • Outros
    • Aconselhamento
      • Auditoria e consultoria
  • Indústrias
    • Fintech e Banca
    • E-commerce
    • Adtech
    • Tecnologia da saúde
    • Fabrico
    • Logística
    • Automóvel
    • IOT
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • A nossa equipa
  • Case Studies
  • Saber como
    • Blogue
    • Encontros
    • Webinars
    • Recursos
Carreiras Entrar em contacto
  • Sobre nós
  • Serviços
    • Desenvolvimento de software
      • Desenvolvimento de front-end
      • Desenvolvimento backend
    • Staff Augmentation
      • Programadores Frontend
      • Programadores de back-end
      • Engenheiros de dados
      • Engenheiros de nuvem
      • Engenheiros de GQ
      • Outros
    • Aconselhamento
      • Auditoria e consultoria
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • A nossa equipa
  • Case Studies
  • Saber como
    • Blogue
    • Encontros
    • Webinars
    • Recursos
Carreiras Entrar em contacto
Seta para trás VOLTAR
2022-07-26
Desenvolvimento de software

Contentores de teste - Como tornar os testes mais fáceis?

Bartlomiej Kuczynski

Está à procura de uma forma de fazer testes de uma maneira mais fácil? Nós temos a solução! Consulte o seguinte artigo e saiba como torná-lo possível.

O desenvolvimento moderno de aplicações baseia-se numa regra simples:

Utilizar a composição

Compomos classes, funções e serviços em peças maiores de software. Este último elemento é a base do microsserviços e arquitetura hexagonal. Gostaríamos de utilizar as soluções existentes, integrá-las no nosso software e passar diretamente para o mercado.

Pretende gerir o registo de contas e armazenar os dados dos utilizadores? Pode escolher um dos serviços OAuth. Talvez a sua aplicação ofereça algum tipo de subscrição ou pagamento? Existem muitos serviços que o podem ajudar a lidar com isso. Precisa de algumas análises no seu sítio Web, mas não compreende o RGPD? Sinta-se à vontade e escolha uma das soluções prontas a utilizar.

Algo que torna o desenvolvimento tão fácil do ponto de vista empresarial pode dar-nos uma dor de cabeça - no momento em que precisamos de escrever um simples teste.

O Fantastic Beasts: Filas de espera, bases de dados e como as testar

Os testes unitários são bastante simples. Se apenas seguir as regras, então o seu ambiente de teste e código são saudáveis. Que regras são essas?

  • Fácil de escrever - um teste unitário deve ser fácil de escrever porque se escrevem muitos deles. Menos esforço significa que mais testes são escritos.
  • Legível - o código do teste deve ser fácil de ler. O teste é uma história. Descreve o comportamento do software e pode ser utilizado como um atalho para a documentação. Um bom teste unitário ajuda-o a corrigir erros sem ter de depurar o código.
  • Fiável - o teste só deve falhar se houver um erro no sistema que está a ser testado. É óbvio? Nem sempre. Por vezes, os testes passam se os executarmos um a um, mas falham quando os executamos como um conjunto. Eles passam na sua máquina, mas falham no CI (Funciona no meu computador). Um bom teste unitário tem apenas uma razão para falhar.
  • Rápido - Os testes devem ser rápidos. A preparação para a execução, o início e a própria execução dos testes devem ser muito rápidos. Caso contrário, os testes serão escritos, mas não executados. Testes lentos significam perda de foco. Espera-se e olha-se para a barra de progresso.
  • Independente - por último, o teste deve ser independente. Esta regra decorre das anteriores. Só os testes verdadeiramente independentes podem constituir uma unidade. Não interferem uns com os outros, podem ser executados em qualquer ordem e as potenciais falhas não dependem dos resultados de outros testes. Independente também significa não depender de quaisquer recursos externos como bases de dados, serviços de mensagens ou sistema de ficheiros. Se precisar de comunicar com recursos externos, pode utilizar mocks, stubs ou dummies.

Tudo se torna complicado quando queremos escrever alguns testes de integração. Não é mau se quisermos testar alguns serviços em conjunto. Mas quando precisamos de testar serviços que utilizam recursos externos como bases de dados ou serviços de mensagens, então estamos a pedir problemas.

Para efetuar o teste, é necessário instalar...

Há muitos anos, quando queríamos efetuar alguns testes de integração e utilizar, por exemplo, bases de dados, tínhamos duas opções:

  1. Podemos instalar uma base de dados localmente. Configure um esquema e ligue-se a partir do nosso teste;
  2. Podemos ligar-nos a uma instância existente "algures no espaço".

Ambos têm prós e contras. Mas ambas introduzem níveis adicionais de complexidade. Por vezes, tratava-se de uma complexidade técnica decorrente das caraterísticas de determinadas ferramentas, por exemplo, a instalação e gestão de uma base de dados Oracle no seu servidor local. Por vezes, tratava-se de um inconveniente no processo, por exemplo, a necessidade de concordar com o teste equipa sobre a utilização de JMS... de cada vez que quiser executar testes.

Contentores para o salvamento

Nos últimos 10 anos, a ideia de contentorização ganhou reconhecimento na indústria. Assim, uma decisão natural é escolher os contentores como uma solução para o nosso problema de teste de integração. Esta é uma solução simples e limpa. Basta executar a construção do processo e tudo funciona! Não acredita? Veja esta configuração simples de uma compilação maven:

com.dkanejs.maven.plugins
     docker-compose-maven-plugin
     4.0.0
     
       
         up
         testar-compilar
         
           acima
         
         
           ${projeto.basedir}/docker-compose.yml
           verdadeiro
         
       
       
         down
         pós-teste de integração
         
           descer
         
         
           ${project.basedir}/docker-compose.yml
           true

E o docker-compose.yml o ficheiro também parece muito bonito!

versão: "3.5"

serviços:

 postgres:
   nome_do_contentor: reactivedb
   imagem: postgres:13.2
   reiniciar: sempre
   ambiente:
     - POSTGRES_USER=admin
     - POSTGRES_PASSWORD=palavra-passe
     - POSTGRES_DB=cidades
   portos:
     - "5432:5432"
   volumes:
     - postgres_data:/data/db

 pgadmin:
   nome_do_contentor: pgadmin4
   imagem: dpage/pgadmin4
   restart: sempre
   ambiente:
     PGADMIN_DEFAULT_EMAIL: [email protected]
     PGADMIN_DEFAULT_PASSWORD: password
   portas:
     - "15050:80"
   volumes:
     - pgadmin_data:/data/pgadmin

volumes:
 postgres_data:
 pgadmin_data:

Mas consegues identificar o problema aqui?

Um cargueiro que bloqueia tudo

O exemplo acima é muito simples. Apenas uma base de dados postgres, pgAdmin e mais nada. Quando se executa

bash
$ mvn clean verify

então o plugin maven inicia os contentores e, após os testes, desliga-os. Os problemas começam quando o projeto cresce e o nosso ficheiro de composição também cresce. Cada vez será necessário iniciar todos os contêineres, e eles permanecerão ativos durante toda a construção. É possível melhorar um pouco a situação alterando a configuração de execução do plugin, mas isso não é suficiente. Na pior das hipóteses, os seus contentores esgotam os recursos do sistema antes do início dos testes!

E este não é o único problema. Não é possível executar um único teste de integração a partir do seu IDE. Antes disso, é necessário iniciar os contentores manualmente. Além disso, a próxima execução do maven irá derrubar esses contentores (dê uma olhada em para baixo execução).

Assim, esta solução é como um grande navio de carga. Se tudo funcionar bem, então está tudo bem. Qualquer comportamento inesperado ou invulgar leva nós a algum tipo de desastre.

Testar contentores - executar contentores a partir de testes

Mas e se pudéssemos executar os nossos contentores a partir de testes? Esta ideia parece boa, e já está a ser implementada. Contentores de testeComo estamos a falar deste projeto, aqui está uma solução para os nossos problemas. Não é ideal, mas ninguém é perfeito.

Este é um Java que suporta testes JUnit e Spock, fornecendo maneiras leves e fáceis de executar o Docker contentor. Vamos dar uma olhadela e escrever algum código!

Pré-requisitos e configuração

Antes de começarmos, precisamos de verificar a nossa configuração. Contentores de ensaio necessidade:

  • Docker na versão v17.09,
  • Versão mínima de Java 1.8,
  • Acesso à rede, especialmente ao docker.hub.

Para mais informações sobre os requisitos de um SO e de um IC específicos, consultar
em documentação.

Agora é altura de adicionar algumas linhas ao pom.xml.

Utilizo o spring boot no projeto para reduzir o boilerplate. Contentores de ensaio são independentes do Spring Framework e podem ser utilizadas sem ele.
org.testcontainers
       testcontainers-bom
       ${testcontaines.version}
       pom
       importar
     
   
 
 
   
     org.postgresql
     postgresql
     tempo de execução
   
   
     org.testcontainers
     postgresql
     teste
   
   
     org.testcontainers
     junit-jupiter
     teste

Eu uso Contentores de ensaio versão 1.17.3mas não hesite em utilizar a mais recente.

Testes com o contentor Postgres

O primeiro passo é preparar a nossa instância de um contentor. Pode fazê-lo diretamente no teste, mas uma classe independente parece melhor.

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_USERNAME", TC.getUsername());
   System.setProperty("DB_PASSWORD", TC.getPassword());
 }

 @Override
 public void stop() {
   // não faz nada. Esta é uma instância partilhada. Deixe a JVM lidar com esta operação.
 }
}

No início dos testes, vamos criar uma instância de Postgres13TC. Esta classe pode tratar as informações sobre o nosso contentor. O mais importante aqui são as strings de conexão com o banco de dados e as credenciais. Agora é hora de escrever um teste muito simples.

@Testcontainers
classe SimpleDbTest {

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

 @Teste
 void testConnection() {
   assumeThat(postgres13TC.isRunning());
   var connectionProps = new Properties();
   connectionProps.put("user", postgres13TC.getUsername());
   connectionProps.put("password", 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();
   }
 }
}

Neste caso, utilizo o JUnit 5. Anotação @Testcontainers é uma parte das extensões que controlam os contentores no ambiente de teste. Elas encontram todos os campos com @Contentor e contentores de início e paragem, respetivamente.

Testes com o Spring Boot

Como referi anteriormente, utilizo o Spring Boot no projeto. Neste caso, precisamos de escrever um pouco mais de código. O primeiro passo é criar uma classe de configuração adicional.

@Slf4j
public class ContainerInit implements
   ApplicationContextInitializer {

 public static Postgres13TC;

 estático {
   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 classe substitui as propriedades existentes por valores da classe recipiente de ensaio. As três primeiras propriedades são propriedades padrão do Spring. As cinco seguintes são propriedades adicionais e personalizadas que podem ser utilizadas para configurar outros recursos e extensões como o liquibase, por exemplo:

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

Agora é altura de definir um teste de integração simples.

@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureTestDatabase(replace = NONE)
@ContextConfiguration(initializers = ContainerInit.class)
@ContentoresTeste
classe DummyRepositoryTest {

 @Autowired
 private DummyRepository;

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

Temos aqui algumas anotações extra.

  • @SpringBootTest(webEnvironment = RANDOM_PORT) - marca o teste como um teste Spring Boot e inicia o contexto do Spring.
  • @AutoConfigureTestDatabase(replace = NONE) - estas anotações dizem que a extensão spring test não deve substituir a configuração da base de dados postgres por H2 na configuração da memória.
  • @ContextConfiguration(initializers = ContainerInit.class) - um contexto de mola adicional
    onde definimos as propriedades de Contentores de ensaio.
  • @Testcontainers - como mencionado anteriormente, esta anotação controla o ciclo de vida do contentor.

Neste exemplo, utilizo repositórios reactivos, mas funciona da mesma forma com repositórios JDBC e JPA comuns.

Agora podemos executar este teste. Se for a primeira execução, o mecanismo precisa extrair imagens do docker.hub. Isso pode demorar um pouco. Depois disso, veremos que dois containers foram executados. Um é o postgres e o outro é o controlador Testcontainers. Esse segundo contêiner gerencia os contêineres em execução e, mesmo que a JVM pare inesperadamente, ele desliga os contêineres e limpa o ambiente.

Resumindo

Contentores de ensaio são ferramentas muito fáceis de utilizar que nos ajudam a criar testes de integração que utilizam contentores Docker. Isto dá-nos mais flexibilidade e aumenta a velocidade de desenvolvimento. A definição correta da configuração dos testes reduz o tempo necessário para integrar novos programadores. Eles não precisam de configurar todas as dependências, basta executar os testes escritos com ficheiros de configuração selecionados.

faixa de cooperação

Artigos relacionados

Ilustração de uma aplicação de cuidados de saúde para smartphone com um ícone de coração e um gráfico de saúde em ascensão, com o logótipo The Codest, representando soluções digitais de saúde e HealthTech.
Desenvolvimento de software

Softwares para o setor de saúde: Tipos, casos de uso

As ferramentas em que as organizações de cuidados de saúde confiam atualmente não se assemelham em nada às fichas de papel de há décadas atrás. O software de cuidados de saúde apoia agora os sistemas de saúde, os cuidados aos doentes e a prestação de cuidados de saúde modernos em...

OCODEST
Ilustração abstrata de um gráfico de barras em declínio com uma seta ascendente e uma moeda de ouro que simboliza a eficiência ou a poupança de custos. O logótipo The Codest aparece no canto superior esquerdo com o slogan "In Code We Trust" sobre um fundo cinzento claro
Desenvolvimento de software

Como dimensionar a sua equipa de desenvolvimento sem perder a qualidade do produto

Aumentar a sua equipa de desenvolvimento? Saiba como crescer sem sacrificar a qualidade do produto. Este guia cobre sinais de que é hora de escalar, estrutura da equipe, contratação, liderança e ferramentas - além de como o The Codest pode...

OCODEST
Desenvolvimento de software

Construir aplicações Web preparadas para o futuro: ideias da equipa de especialistas do The Codest

Descubra como o The Codest se destaca na criação de aplicações web escaláveis e interactivas com tecnologias de ponta, proporcionando experiências de utilizador perfeitas em todas as plataformas. Saiba como a nossa experiência impulsiona a transformação digital e o negócio...

OCODEST
Desenvolvimento de software

As 10 principais empresas de desenvolvimento de software sediadas na Letónia

Saiba mais sobre as principais empresas de desenvolvimento de software da Letónia e as suas soluções inovadoras no nosso último artigo. Descubra como estes líderes tecnológicos podem ajudar a elevar o seu negócio.

thecodest
Soluções para empresas e escalas

Fundamentos do desenvolvimento de software Java: Um Guia para Terceirizar com Sucesso

Explore este guia essencial sobre o desenvolvimento de software Java outsourcing com sucesso para aumentar a eficiência, aceder a conhecimentos especializados e impulsionar o sucesso do projeto com The Codest.

thecodest

Subscreva a nossa base de conhecimentos e mantenha-se atualizado sobre os conhecimentos do sector das TI.

    Sobre nós

    The Codest - Empresa internacional de desenvolvimento de software com centros tecnológicos na Polónia.

    Reino Unido - Sede

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

    Polónia - Pólos tecnológicos locais

    • Parque de escritórios Fabryczna, Aleja
      Pokoju 18, 31-564 Cracóvia
    • Embaixada do Cérebro, Konstruktorska
      11, 02-673 Varsóvia, Polónia

      The Codest

    • Início
    • Sobre nós
    • Serviços
    • Case Studies
    • Saber como
    • Carreiras
    • Dicionário

      Serviços

    • Aconselhamento
    • Desenvolvimento de software
    • Desenvolvimento backend
    • Desenvolvimento de front-end
    • Staff Augmentation
    • Programadores de back-end
    • Engenheiros de nuvem
    • Engenheiros de dados
    • Outros
    • Engenheiros de GQ

      Recursos

    • Factos e mitos sobre a cooperação com um parceiro externo de desenvolvimento de software
    • Dos EUA para a Europa: Porque é que as empresas americanas decidem mudar-se para a Europa?
    • Comparação dos centros de desenvolvimento da Tech Offshore: Tech Offshore Europa (Polónia), ASEAN (Filipinas), Eurásia (Turquia)
    • Quais são os principais desafios dos CTOs e dos CIOs?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Direitos de autor © 2026 por The Codest. Todos os direitos reservados.

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