In het begin zal het geweldig werken, maar na een aantal releases begint productie links en rechts om te vallen. We kunnen niet vertrouwen op onze testen om integratieregressie vast te stellen, aangezien onze applicaties niet meer gekoppeld zijn. Als een API-provider een breaking change maakt in een API waarvan we afhankelijk zijn, kunnen onze testen het probleem niet ondervangen. Dit gebeurt omdat er tijdens het testen geen coupling is tussen onze applicaties, en daar zal productie onder lijden.
Neem bijvoorbeeld een situatie waarin de provider update Amazing 1.5.0 uitbrengt terwijl onze stubs nog steeds werken volgens de specs van Amazing 1.4.0. Dit heet stub drift; de stubs zijn stilletjes afgedreven van de realiteit van de productie.
Het goede deel
De eerste keer dat je overschakelt van end-to-end testen naar deze manier van testen, voelt het geweldig. Je kunt plotseling veel sneller testen maken omdat je de volledige controle hebt over alle onderdelen van de test. Het uitvoeren van deze testen gaat ook sneller omdat alles lokaal draait. We praten ineens over milliseconden in plaats van seconden. Het is geweldig! En het allerbeste: geen hoofdpijn meer.
Tranen
Maar, zoals eerder vermeld, zal deze euforie niet lang duren.
Het eerste dat opvalt, is dat je niet alle bestaande testen op deze manier kunt reproduceren. Sommige testen zijn alleen nuttig wanneer gegevens door meerdere applicaties stromen. Aangezien je jouw testen nu geïsoleerd uitvoert, is dat onmogelijk. Sommige soorten testen kunnen per definitie niet in isolatie worden uitgevoerd. Je zult een aantal end-to-end testen moeten houden, maar er zijn er in ieder geval veel minder.
Na een tijdje beginnen de productieproblemen binnen te komen. Een andere applicatie heeft een nieuwe versie uitgebracht en dat heeft een deel van de API die je gebruikt kapot gemaakt. Het is een typefoutje van een ontwikkelaar. De testen van de API-providers hebben het niet opgevangen en jouw testen ook niet. Normaal gesproken had je dit ontdekt met de end-to-end testen, maar voor deze situatie bestaan die niet meer. Jij en je team werken hard om het probleem direct op te lossen en het enige dat je productowner kan doen, is thee en pizza voor het avondeten halen. Jij bent ongelukkig, jouw team is ongelukkig en de eindgebruikers zijn ongelukkig.
Droog je tranen
Je kunt integratieregressie niet opvangen als je test zonder coupling tussen de API-provider en de consumer. Dit leidt tot valse positieven in jouw testen en dus tot productieproblemen. Er zijn meer manieren waarop volledige isolatie tegen je werkt. Maar om het kort te houden: een testpatroon met zo’n groot potentieel voor valse positieven, is geen geschikt patroon.
Laten we dus een manier zoeken om onze applicatie te testen die ons geen hoofdpijn bezorgt en ons niet laat huilen. Als we terugkijken op wat we tot nu toe hebben gezien, weten we dat we hoofdpijn krijgen als we tightly coupled zijn (end-to-end). En als we helemaal niet coupled zijn (volledige isolatie) eet het hele team pizza. Zoals bij veel dingen in het leven, ligt de oplossing ergens in het midden. Contract-based testen is zo’n oplossing.
"Zoals bij veel dingen in het leven, ligt de oplossing ergens in het midden. Contract-based testen is zo'n oplossing."
Contract-based testen
Bij contract-based testen koppelen we elke applicatie met één bestand: een contract. Op deze manier zijn onze applicaties wel coupled, maar lang niet zo strak als bij end-to-end testen.
Als je het je herinnert van deel 1; het contract is het gedeelde begrip van de interface tussen de provider en de consumer. Beide partijen kunnen dit gedeelde begrip gebruiken bij hun implementatie en testen. Dat doen ze terwijl ze ervoor zorgen dat de enige coupling via het contract is.
Omdat we enige coupling hebben, zullen we interfaceregressie opvangen in onze contracttesten. Ook houden we de aanzienlijke voordelen van geïsoleerd testen. Met name de onafhankelijkheid van andere teams leidt tot een veel snellere testcreatie.
Conclusie
We hebben meerdere manieren bekeken om volledige applicaties te testen. End-to-end testen zijn per definitie tightly coupled. Hierdoor zijn ze krachtig, maar ook tijdrovend. Wanneer we van onze end-to-end omgeving afstappen, merken we dat we plotseling volledig geïsoleerd zijn zonder enige coupling. Dit veroorzaakt veel problemen, waarvan de grootste leiden tot valse positieven in jouw testen.
Contract-based testen is een oplossing die resulteert in enige coupling, maar niet zo strak als bij end-to-end testen. Dit stelt ons in staat om veel van de nadelen van end-to-end testen te vermijden en tegelijkertijd de vele voordelen van geïsoleerd testen te behouden.
In deel 4 van mijn blogreeks bespreek ik hoe contract-based testen werkt, de benaderingen, de sterke en de zwakke punten. En ik zal het niet meer hebben over hoofdpijn, tranen of pizza. Beloofd.
Met dank aan Vilas Pultoo voor de illustraties
Ben jij geïnteresseerd in contract-based testen?
Luister dan ook onze podcast waarin Sander van Beek en Stephan Dammers in gesprek gaan over dit onderwerp. Sander maakt jou wegwijs in de wereld van contract-based testen en vertelt uitgebreid over zijn ervaringen, wanneer contract-based testen wordt ingezet, de te verwachtte trends en nog veel meer. Je luistert de podcast via ons SoundCloud account.