Met de komst van Testcontainers is het mogelijk om externe services te starten op lokale Docker containers. Door een consistente testomgeving te bieden, verkleint Testcontainers de kans op ‘werkt op mijn machine’-problemen, wat zorgt voor betrouwbaardere en reproduceerbare testresultaten. Testcontainers kan eenvoudig worden geïntegreerd met populaire testframeworks zoals JUnit.
Door gebruik te maken van Docker-containers kunnen complexe services zoals databases, web-servers of zelfs hele applicaties worden opgestart zonder ingewikkelde installatieprocessen of configuraties op de lokale machine of in de CI/CD-pijplijn.
Een simpel java voorbeeld
Laten we eens kijken naar een simpel java voorbeeld met een dependency op Redis. We gebruiken hiervoor Jedis als client.
Allereerst importeren we de benodigde maven dependencies:
Daarna maken we een simpele class aan met daarin een dependency op de Redis service:
Hier gebeuren een aantal interessante dingen. In de try-with-resources wordt de container gedefinieerd. Met de .withExposedPorts() methode geven we de port binnen de container op. Testcontainers zal deze port mappen naar een willekeurige port op de host machine.
Met .getHost() en .getMappedPort(6379) op het container object krijgen we de waarde van de host en de random port. Omdat we maar 1 port hebben ge-exposed kun je in plaats van .getMappedPort(6379) ook .getFirstMappedPort() gebruiken.
Kijken we naar de output van ‘docker ps’ dan zien we dat er 2 containers worden opgestart.
Ryuk als hulpprogramma
Kijken we naar de output van ‘docker ps’ dan zien we dat er 2 containers worden opgestart.
De eerste is zoals verwacht onze Redis container. Daarnaast start Testcontainers ook een ryuk container op.
Testcontainers gebruikt Ryuk als hulpprogramma om ervoor te zorgen dat alle containers die tijdens de tests worden gecreëerd, automatisch en op betrouwbare wijze worden gestopt en verwijderd wanneer de testrun voltooid is. Aangezien Ryuk onafhankelijk van de testprocessen draait, kan het opruimen zelfs doorgaan als het testproces onverwacht stopt of crasht.
Voordelen bij integratie testen
Het voorbeeld hierboven is bewust simpel gehouden om de leesbaarheid te vergroten en lijkt daardoor vooral op een unit test, maar Testcontainers komt pas echt tot zijn recht bij integratie testen.
Alle onderdelen van de integratietest inclusief externe services kunnen met Testcontainers lokaal worden gestart. Denk hierbij bijvoorbeeld aan het testen van een ETL-applicatie welke afhankelijk is van PostgreSQL, Kafka en Elasticsearch. Een ander voordeel is dat bij een aanstaande upgrade van een van deze drie services je snel en vooraf kunt testen of de applicatie goed met de upgrade overweg kan.
Conclusie
Testcontainers is een essentieel gereedschap voor moderne softwareontwikkeling, dat ontwikkelaars in staat stelt om sneller te werken. Of het nu gaat om het testen van kleine componenten of het valideren van de werking van een gehele applicatie in een geïntegreerde omgeving, Testcontainers verhoogt de efficiëntie en betrouwbaarheid van het testproces. Dit maakt het een onmisbare stuk gereedschap voor elke ontwikkelaar die streeft naar het leveren van hoogwaardige en betrouwbare software.