window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = finestra if (w.LeadBooster) { console.warn('LeadBooster esiste già') } 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 }) }, } } })() Contenitori di test - Come semplificare i test? - The Codest
The Codest
  • Chi siamo
  • Servizi
    • Sviluppo di software
      • Sviluppo Frontend
      • Sviluppo backend
    • Staff Augmentation
      • Sviluppatori Frontend
      • Sviluppatori backend
      • Ingegneri dei dati
      • Ingegneri del cloud
      • Ingegneri QA
      • Altro
    • Consulenza
      • Audit e consulenza
  • Industrie
    • Fintech e banche
    • E-commerce
    • Adtech
    • Tecnologia della salute
    • Produzione
    • Logistica
    • Automotive
    • IOT
  • Valore per
    • CEO
    • CTO
    • Responsabile della consegna
  • Il nostro team
  • Case Studies
  • Sapere come
    • Blog
    • Incontri
    • Webinar
    • Risorse
Carriera Contattate
  • Chi siamo
  • Servizi
    • Sviluppo di software
      • Sviluppo Frontend
      • Sviluppo backend
    • Staff Augmentation
      • Sviluppatori Frontend
      • Sviluppatori backend
      • Ingegneri dei dati
      • Ingegneri del cloud
      • Ingegneri QA
      • Altro
    • Consulenza
      • Audit e consulenza
  • Valore per
    • CEO
    • CTO
    • Responsabile della consegna
  • Il nostro team
  • Case Studies
  • Sapere come
    • Blog
    • Incontri
    • Webinar
    • Risorse
Carriera Contattate
Freccia indietro TORNA INDIETRO
2022-07-26
Sviluppo di software

Contenitori di test - Come semplificare i test?

Bartlomiej Kuczynski

Siete alla ricerca di un modo per realizzare i test in modo più semplice? Abbiamo trovato il modo! Consultate il seguente articolo e scoprite come renderlo possibile.

Lo sviluppo di applicazioni moderne si basa su una semplice regola:

Utilizzare la composizione

Componiamo classi, funzioni e servizi in pezzi di software più grandi. Quest'ultimo elemento è il fondamento dei microservizi e dei servizi. architettura esagonale. Vorremmo utilizzare le soluzioni esistenti, integrarle con il nostro software e passare direttamente alla mercato.

Volete gestire la registrazione dell'account e memorizzare i dati dell'utente? Potete scegliere uno dei servizi OAuth. Forse la vostra applicazione offre un qualche tipo di abbonamento o di pagamento? Ci sono molti servizi che possono aiutarvi a gestire questo aspetto. Avete bisogno di analisi sul vostro sito web, ma non conoscete il GDPR? Non esitate a scegliere una delle soluzioni pronte all'uso.

Qualcosa che rende lo sviluppo così facile da un punto di vista commerciale potrebbe farvi venire il mal di testa nel momento in cui dovete scrivere un semplice test.

Le bestie fantastiche: Code, database e come testarli

I test unitari sono piuttosto semplici. Se ci si attiene solo alle regole, l'ambiente di test e il codice sono sane. Quali sono le regole?

  • Facile da scrivere - un test unitario dovrebbe essere facile da scrivere, perché se ne scrivono molti. Meno sforzo significa scrivere più test.
  • Leggibile - il codice di test deve essere facile da leggere. Il test è una storia. Descrive il comportamento del software e può essere usato come scorciatoia per la documentazione. Un buon test unitario aiuta a risolvere i bug senza dover eseguire il debug del codice.
  • Affidabile - il test dovrebbe fallire solo se c'è un bug nel sistema che si sta testando. È ovvio? Non sempre. A volte i test passano se li si esegue uno per uno, ma falliscono quando li si esegue come un insieme. Passano sulla vostra macchina, ma falliscono sul CI (Funziona sul mio computer). Un buon test unitario ha un solo motivo di fallimento.
  • Veloce - i test devono essere veloci. La preparazione all'esecuzione, l'avvio e l'esecuzione stessa dei test devono essere molto rapidi. Altrimenti li scriverete, ma non li eseguirete. Test lenti significano perdita di concentrazione. Si aspetta e si guarda la barra di avanzamento.
  • Indipendente - infine, il test deve essere indipendente. Questa regola deriva dalle precedenti. Solo i test veramente indipendenti possono diventare un'unità. Non interferiscono tra loro, possono essere eseguiti in qualsiasi ordine e i potenziali fallimenti non dipendono dai risultati di altri test. Indipendente significa anche nessuna dipendenza da risorse esterne come database, servizi di messaggistica o file system. Se è necessario comunicare con gli esterni, si possono usare mock, stub o dummies.

Tutto si complica quando vogliamo scrivere dei test di integrazione. Non è male se vogliamo testare alcuni servizi insieme. Ma quando dobbiamo testare servizi che utilizzano risorse esterne, come database o servizi di messaggistica, allora ci troviamo in difficoltà.

Per eseguire il test, è necessario installare...

Molti anni fa, quando volevamo realizzare alcuni test di integrazione e utilizzare, ad esempio, i database, avevamo due opzioni:

  1. Possiamo installare un database in locale. Impostare uno schema e connettersi dal nostro test;
  2. Possiamo collegarci a un'istanza esistente "da qualche parte nello spazio".

Entrambi hanno dei pro, entrambi hanno dei contro. Ma entrambi introducono ulteriori livelli di complessità. A volte si trattava di complessità tecnica derivante dalle caratteristiche di alcuni strumenti, ad esempio l'installazione e la gestione di un DB Oracle su localhost. A volte si trattava di un inconveniente nel processo, ad esempio la necessità di accordarsi con il test squadra sull'uso di JMS... ogni volta che si vogliono eseguire i test.

Contenitori in soccorso

Negli ultimi 10 anni, l'idea della containerizzazione si è affermata nel settore. Quindi, la decisione naturale è quella di scegliere i container come soluzione per il nostro problema di test di integrazione. Si tratta di una soluzione semplice e pulita. Basta eseguire la build del processo e tutto funziona! Non ci credete? Date un'occhiata a questa semplice configurazione di una build di maven:

com.dkanejs.maven.plugins
     docker-compose-maven-plugin
     4.0.0
     
       
         up
         test-compile
         
           up
         
         
           ${progetto.basedir}/docker-compose.yml
           true
         
       
       
         down
         post-integrazione-test
         
           down
         
         
           ${project.basedir}/docker-compose.yml
           true

E il docker-compose.yml Anche il file è molto bello!

versione: "3.5"

servizi:

 postgres:
   nome_contenitore: reactivedb
   immagine: postgres:13.2
   riavvio: sempre
   ambiente:
     - UTENTE_POSTGRES=admin
     - POSTGRES_PASSWORD=password
     - POSTGRES_DB=città
   porte:
     - "5432:5432"
   volumi:
     - postgres_data:/data/db

 pgadmin:
   nome_contenitore: pgadmin4
   immagine: dpage/pgadmin4
   riavvio: sempre
   ambiente:
     PGADMIN_DEFAULT_EMAIL: [email protected]
     PGADMIN_DEFAULT_PASSWORD: password
   porte:
     - "15050:80"
   volumi:
     - pgadmin_data:/data/pgadmin

volumi:
 postgres_data:
 pgadmin_data:

Ma riuscite a individuare il problema?

Una nave da carico che blocca tutto

L'esempio precedente è molto semplice. Solo un database postgres, pgAdmin e tutto il resto. Quando si esegue

bash
$ mvn clean verify

poi il plugin di maven avvia i contenitori e dopo i test li spegne. I problemi iniziano quando il progetto cresce e anche il nostro file di composizione cresce. Ogni volta è necessario avviare tutti i contenitori, che rimarranno in vita per l'intera compilazione. Si può migliorare un po' la situazione modificando la configurazione di esecuzione dei plugin, ma non è sufficiente. Nel peggiore dei casi, i contenitori esauriscono le risorse del sistema prima dell'avvio dei test!

E questo non è l'unico problema. Non è possibile eseguire un singolo test di integrazione dall'IDE. Prima di ciò, è necessario avviare i contenitori a mano. Inoltre, l'esecuzione successiva di maven distruggerà i contenitori (si veda la sezione giù esecuzione).

Quindi questa soluzione è come una grande nave da carico. Se tutto funziona bene, allora è tutto ok. Qualsiasi comportamento inaspettato o insolito ci porta a un qualche tipo di disastro.

Contenitori di test: eseguire i contenitori dai test

Ma cosa succederebbe se potessimo eseguire i nostri container dai test? L'idea sembra buona e viene già implementata. Contenitori di provaPoiché stiamo parlando di questo progetto, ecco una soluzione per i nostri problemi. Non è l'ideale, ma nessuno è perfetto.

Questo è un Java che supporta i test JUnit e Spock, fornendo modi leggeri e semplici per eseguire il contenitore Docker. Diamogli un'occhiata e scriviamo un po' di codice!

Prerequisiti e configurazione

Prima di iniziare, dobbiamo verificare la nostra configurazione. Contenitori di prova necessità:

  • Docker nella versione v17.09,
  • Java versione minima 1.8,
  • Accesso alla rete, in particolare a docker.hub.

Per maggiori informazioni sui requisiti per i sistemi operativi e gli IC specifici, consultare la sezione
in documentazione.

Ora è il momento di aggiungere alcune righe a pom.xml.

Uso Spring Boot nel progetto per ridurre il boilerplate. Contenitori di prova sono indipendenti da Spring Framework e si possono usare anche senza.
org.testcontainers
       testcontainers-bom
       ${testcontaines.version}
       pom
       import
     
   
 
 
   
     org.postgresql
     postgresql
     runtime
   
   
     org.testcontainers
     postgresql
     test
   
   
     org.testcontainers
     junit-jupiter
     test

Uso Contenitori di prova versione 1.17.3, ma sentitevi liberi di usare quello più recente.

Test con il contenitore Postgres

Il primo passo è preparare l'istanza di un contenitore. È possibile farlo direttamente nel test, ma è meglio utilizzare una classe indipendente.

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() {
   // non fa nulla. Questa è un'istanza condivisa. Lasciamo che sia la JVM a gestire questa operazione.
 }
}

All'inizio dei test, creeremo un'istanza di Postgres13TC. Questa classe può gestire le informazioni sul nostro contenitore. Le più importanti sono le stringhe di connessione al database e le credenziali. Ora è il momento di scrivere un test molto semplice.

@Contenitori di test
classe SimpleDbTest {

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

 @Test
 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();
   }
 }
}

Qui uso JUnit 5. Annotazione @Testcontainers fa parte delle estensioni che controllano i contenitori nell'ambiente di test. Trovano tutti i campi con @Contenitore e i contenitori start e stop, rispettivamente.

Test con Spring Boot

Come ho già detto, nel progetto utilizzo Spring Boot. In questo caso, dobbiamo scrivere un po' di codice in più. Il primo passo è creare una classe di configurazione aggiuntiva.

@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()
   );
 }
}

Questa classe sovrascrive le proprietà esistenti con i valori della classe contenitore di prova. Le prime tre proprietà sono proprietà standard di Spring. Le cinque successive sono proprietà aggiuntive e personalizzate, che possono essere utilizzate per configurare altre risorse ed estensioni come liquibase, ad esempio:

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

Ora è il momento di definire un semplice test di integrazione.

@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureTestDatabase(replace = NONE)
@ContextConfiguration(initializers = ContainerInit.class)
@Contenitori di test
class DummyRepositoryTest {

 @Autowired
 private DummyRepository;

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

Qui abbiamo alcune annotazioni aggiuntive.

  • @SpringBootTest(webEnvironment = RANDOM_PORT) - contrassegna il test come test Spring Boot e avvia il contesto Spring.
  • @AutoConfigureTestDatabase(replace = NONE) - queste annotazioni dicono che l'estensione Spring Test non deve sostituire la configurazione del database postgres con H2 nella configurazione della memoria.
  • @ContextConfiguration(initializers = ContainerInit.class) - un ulteriore contesto di primavera
    in cui si impostano le proprietà da Contenitori di prova.
  • @Testcontainers - come già detto, questa annotazione controlla il ciclo di vita del contenitore.

In questo esempio, utilizzo repository reattivi, ma funziona allo stesso modo con i comuni repository JDBC e JPA.

Ora possiamo eseguire il test. Se è la prima esecuzione, il motore deve prelevare le immagini da docker.hub. Potrebbe volerci un attimo. Dopodiché, vedremo che sono stati eseguiti due contenitori. Uno è postgres e l'altro è il controller Testcontainers. Il secondo contenitore gestisce i contenitori in esecuzione e, anche se la JVM si arresta inaspettatamente, spegne i contenitori e pulisce l'ambiente.

Riassumiamo

Contenitori di prova sono strumenti molto semplici da usare che ci aiutano a creare test di integrazione che utilizzano i container Docker. Questo ci offre maggiore flessibilità e aumenta la velocità di sviluppo. L'impostazione corretta della configurazione dei test riduce il tempo necessario per i nuovi sviluppatori. Non devono impostare tutte le dipendenze, ma solo eseguire i test scritti con i file di configurazione selezionati.

banner di cooperazione

Articoli correlati

Sviluppo di software

Costruire applicazioni web a prova di futuro: le intuizioni del team di esperti di The Codest

Scoprite come The Codest eccelle nella creazione di applicazioni web scalabili e interattive con tecnologie all'avanguardia, offrendo esperienze utente senza soluzione di continuità su tutte le piattaforme. Scoprite come la nostra esperienza favorisce la trasformazione digitale e il business...

IL CANCRO
Sviluppo di software

Le 10 principali aziende di sviluppo software con sede in Lettonia

Scoprite le migliori aziende di sviluppo software della Lettonia e le loro soluzioni innovative nel nostro ultimo articolo. Scoprite come questi leader tecnologici possono aiutarvi a migliorare la vostra attività.

thecodest
Soluzioni per aziende e scaleup

Essenziali di sviluppo software Java: Guida all'outsourcing di successo

Esplorate questa guida essenziale sullo sviluppo di software Java con successo outsourcing per migliorare l'efficienza, accedere alle competenze e guidare il successo del progetto con The Codest.

thecodest
Sviluppo di software

La guida definitiva all'outsourcing in Polonia

L'aumento di outsourcing in Polonia è guidato dai progressi economici, educativi e tecnologici, che favoriscono la crescita dell'IT e un clima favorevole alle imprese.

IlCodesto
Soluzioni per aziende e scaleup

Guida completa agli strumenti e alle tecniche di audit IT

Gli audit IT garantiscono sistemi sicuri, efficienti e conformi. Per saperne di più sulla loro importanza, leggete l'articolo completo.

The Codest
Jakub Jakubowicz CTO e cofondatore

Iscrivetevi alla nostra knowledge base e rimanete aggiornati sulle competenze del settore IT.

    Chi siamo

    The Codest - Società internazionale di sviluppo software con centri tecnologici in Polonia.

    Regno Unito - Sede centrale

    • Ufficio 303B, 182-184 High Street North E6 2JA
      Londra, Inghilterra

    Polonia - Poli tecnologici locali

    • Parco uffici Fabryczna, Aleja
      Pokoju 18, 31-564 Cracovia
    • Ambasciata del cervello, Konstruktorska
      11, 02-673 Varsavia, Polonia

      The Codest

    • Casa
    • Chi siamo
    • Servizi
    • Case Studies
    • Sapere come
    • Carriera
    • Dizionario

      Servizi

    • Consulenza
    • Sviluppo di software
    • Sviluppo backend
    • Sviluppo Frontend
    • Staff Augmentation
    • Sviluppatori backend
    • Ingegneri del cloud
    • Ingegneri dei dati
    • Altro
    • Ingegneri QA

      Risorse

    • Fatti e miti sulla collaborazione con un partner esterno per lo sviluppo di software
    • Dagli Stati Uniti all'Europa: Perché le startup americane decidono di trasferirsi in Europa
    • Confronto tra gli hub di sviluppo Tech Offshore: Tech Offshore Europa (Polonia), ASEAN (Filippine), Eurasia (Turchia)
    • Quali sono le principali sfide di CTO e CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Condizioni di utilizzo del sito web

    Copyright © 2025 di The Codest. Tutti i diritti riservati.

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