In questo articolo Marco Rotondi introduce questa libreria fornendo alcune informazioni come prerequisiti e funzionalità il tutto corredato con del codice dimostrativo già oggetto di una presentazione, curata assieme a Luca Cruciani, tenutasi durante l’open conference dell’Intré Camp del 29 ottobre 2019.
Testcontainers
Testcontainers è una libreria Java a supporto dei test con Junit (che non è l’unico framework di test supportato) che permette di eseguire qualsiasi risorsa che possa essere eseguita con un container Docker.
In generale questa libreria permette di testare facilmente lo strato di Data access permettendo di istanziare numerosi database, sia relazionali che non. É possibile inoltre eseguire test end-to-end o di integrazione e, aspetto da non sottovalutare, anche UI test.
Di default la libreria contiene il supporto a molti database e a Selenium WebDriver. Questi ultimi due casi sono oggetto del codice del progetto reperibile dalla pagina aziendale GitHub (trovate il link nel paragrafo Riferimenti).
Testcontainers: prerequisiti
Per poter utilizzare la libreria è fondamentale avere installato Docker sulla propria macchina. È anche possibile eseguire istanze di Docker remote. Questo perché all’inizio dell’esecuzione Testcontainers si occupa di controllare se Docker sia installato/configurato andando a verificare in sequenza:
- Docker socker: docker.sock è il socket UNIX che il daemon Docker sta ascoltando. È il punto di ingresso principale per l’API Docker. Può anche essere socket TCP ma, per impostazione predefinita, per motivi di sicurezza Docker utilizza per impostazione predefinita il socket UNIX. Il client cli Docker utilizza questo socket per eseguire i comandi Docker per impostazione predefinita.
- Variabile di ambiente DOCKER_HOST
Altro prerequisito è l’uso di uno strumento di build come maven o gradle e infine una libreria di test. Le versioni supportate sono:
- JUnit4
- JUnit5
- Spock
In realtà il tutto può essere comandato tramite le annotazioni definite a supporto di questi framework, sia manualmente che via container Docker:
- creando container che esisteranno durante tutto l’arco della durata dei test;
- eseguendo un nuovo container per ogni test definito nella classe.
Testcontainers: architettura e funzionalità
La libreria di test è composta da una parte core e da estensioni separate per ogni modulo, per evitare problemi sulle versioni è disponibile anche il pacchetto pom.
La libreria risulta completa in ogni sua parte e questo permette di avere pieno controllo sui container che vengono definiti ed eseguiti per l’esecuzione dei test.
In particolare è possibile:
- gestire le porte di comunicazione, sia quelle del singolo container che quelle esposte;
- definire network in maniera da mettere in collegamento tra loro più container;
- registrare i log dei singoli container.
Altre funzioni disponibili riguardano l’esecuzione di comandi all’interno del container, gestire i volumi e alcune classi che permettono di restare in attesa del corretto avvio di ogni singolo container.
Queste non sono che le principali caratteristiche, per ulteriori approfondimenti si consiglia la lettura della documentazione sul sito ufficiale (paragrafo Riferimenti).
Testcontainers: un semplice codice di esempio
Premessa: i test scritti nel progetto di esempio utilizzano JUnit5 perciò annotazioni e flussi possono variare qualora venisse utilizzata la versione precedente del framework di test (sul sito è possibile consultare esempi di come utilizzare le varie versioni del framework per ogni tipo di libreria di test).
Nel codice raffigurato si nota lo scheletro di un caso di test che esegue un container che a sua volta esegue un database PostgreSQL di nome gitfcard-test.
Il test in sé è molto semplice, si occupa di verificare che il container sia in esecuzione, recuperare la stringa da usare per una eventuale connessione e accertarsi che tale container contenga il database definito in fase di running.
La proprietà annotata con @Container permette di eseguire il container in automatico all’esecuzione del test.
Tale proprietà è stata definita come semplice variabile privata all’interno della classe, ciò fa si che per ogni test che viene definito un nuovo container venga eseguito. Nel caso la variabile fosse stata di tipo statico allora il container sarebbe stato lo stesso per ogni test.
Per altri esempi che utilizzano Selenium Webdriver e il browser Google Chrome per eseguire alcuni UI test del sito aziendale potete consultare il codice del progetto sulla pagina aziendale su GitHub (link nel paragrafo Riferimenti).
Conclusioni
Testcontainers è una soluzione che permette di eseguire qualsiasi tipo di container durante la fase di test, consentendo di testare il codice in un ambiente reale evitando di dover ricorrere all’utilizzo di classi di Mock per i vari servizi.
La libreria è completa e semplice da usare, l’integrazione con JUnit è ottima e per altri framework di test è comunque possibile ottenere lo stesso risultato scrivendo del codice supplementare. Marco l’ha utilizzata senza alcun problema sia per testare delle query con aggregati su database MongoDB che in un contesto di CI/CD con Jenkins.
Molto potente l”integrazione con Selenium dove, tra le altre, è molto interessante la possibilità di registrare dei video dell’esecuzione dei casi di test per poter poi verificare in maniera semplice il risultato o individuare i vari problemi.
Riferimenti
- Sito ufficiale della libreria Testcontainers
- Progetto di demo su GitHub
- Framework di test per linguaggio Java JUnit5
- Docker