API-testing is de meest onderschatte laag in veel teststrategieën. Sneller, stabieler, en dichter bij de business-logica dan wat er op het scherm te zien is.
Je klikt door de applicatie. Alles werkt. De knoppen reageren, de pagina's laden, het formulier verzendt. Je zou zweren dat het in orde is.
En toch staat er onder de motorkap een API die verkeerde data teruggeeft, een statuscode van 200 stuurt bij een fout, of een veld weglaat dat de mobiele app wél verwacht. De UI verbergt het. Tot een andere client het niet meer verbergt.
Veel teststrategieën stoppen bij de interface. Begrijpelijk: dat is wat je ziet, en wat de gebruiker ziet. Maar de API is de ruggengraat. Dat is waar de business-logica leeft, waar de data doorheen stroomt, waar meerdere clients op aansluiten.
Een API-test draait in milliseconden, terwijl een UI-test seconden nodig heeft. Hij breekt niet omdat de locator van een element werd gewijzigd. En hij test de businessregel zelf, niet de weergave ervan.
De keuze tussen tools is minder een religieuze kwestie dan mensen ervan maken. Ze doen verschillende dingen goed.
Sterk in exploratie. Je wil snel zien wat een endpoint teruggeeft, een header aanpassen, een payload uitproberen. Visueel, laagdrempelig, geen code nodig. Ideaal om een API te leren kennen, en om als team snel iets te delen.
Code-first, in Java, en daarmee volledig thuis in je CI/CD-pipeline. Je tests leven naast je applicatiecode, gaan mee in code review, en draaien automatisch bij elke build. Minder geschikt om even snel iets uit te proberen, veel geschikter om structureel te testen.
In de praktijk gebruiken de meeste teams beide. Dat is geen inconsequentie, dat is het juiste gereedschap voor de juiste taak.
200 bij succes, 201 bij creatie, 400 bij een foute request, 404 bij niet gevonden, 500 bij een serverfout. Klinkt vanzelfsprekend. Is het niet. Een API die 200 teruggeeft met een foutmelding in de body is verrassend gewoon, en verrassend problematisch.
Dit is het contract. Welke velden komen terug, van welk type, welke zijn verplicht. Verandert dat ongemerkt, dan breken je consumers. Een contracttest vangt dat af vóór het productie haalt.
Wat gebeurt er bij een lege payload? Een veld dat te lang is? Een ID dat niet bestaat? Een negatief bedrag? De happy path testen is het makkelijke deel. De edge cases zijn waar het misgaat.
Kan een gebruiker zonder token erbij? Kan gebruiker A de data van gebruiker B opvragen? Dit is niet alleen een testvraag, het is een beveiligingsvraag. En hij wordt te vaak overgeslagen.
Zo ziet een test die drie van de vier categorieën in één keer afdekt er in de praktijk uit: statuscode, response-structuur en autorisatie.
// haalt een gebruiker op en controleert status, structuur én autorisatie
@Test
void gebruikerZonderTokenKrijgtGeenToegang() {
given()
.header("Authorization", "")
.when()
.get("/api/users/123")
.then()
.statusCode(401);
}
@Test
void gebruikerMetTokenKrijgtCorrecteResponse() {
given()
.header("Authorization", "Bearer " + validToken)
.when()
.get("/api/users/123")
.then()
.statusCode(200)
.body("id", equalTo(123))
.body("email", notNullValue())
.body("password", not(hasKey("password")));
}
Twee tests, twee assumpties gecontroleerd: geen token betekent geen toegang, en een geldig token levert exact de velden die het contract belooft — geen wachtwoordveld dat per ongeluk meelekt in de response.
Als je vandaag geen API-tests hebt: begin bij je meest kritieke endpoint. Dat ene waar geld doorheen gaat, of persoonsgegevens, of waar de hele applicatie op leunt. Test de vier categorieën hierboven. Zet het in je pipeline.
Je zult verbaasd zijn hoeveel je vindt in dat ene endpoint.
We nemen je testaanpak door en zeggen eerlijk waar de winst zit. En waar niet.
Plan een gesprek