Sådan automatiseres REST API end-to-end tests i et CI-miljø med Postman og Newman

Postbrevet er et fantastisk værktøj til at udforske REST API'er. Du kan oprette anmodninger og prøve dem for at få hurtig feedback. Derefter kan du fortsætte dem som samlinger for at sikre, at viden ikke går tabt.

Newman, CLI-versionen af ​​Postman, giver dig mulighed for at tage det til næste niveau og omdanne en samling til en række automatiserede end-to-end-tests. Denne suite kører derefter i dit CI-værktøj, du vælger. I denne artikel vil jeg undersøge fordelene ved at gøre det og vise dig, hvordan du konfigurerer det.

intro

Hvad er en End-to-End-test i forbindelse med en API?

Test af nomenklatur er en vanskelig ting. Når vi holder testpyramiden i tankerne, kan vi forestille os dem som test på meget højt niveau. Disse tests bekræfter, at en bestemt REST API fungerer efter hensigten og behandler det indvendige som en sort boks. Vi involverer ikke nogen brugergrænseflade i processen, hvilket hjælper med at reducere flakiness.

poke-e2e

af geek & poke / CC BY

Flaky tests er ekstremt irriterende, som enhver udvikler har oplevet på et eller andet tidspunkt. I stedet for at banke hovedet mod væggen og forsøge at ordne det ikke-faste, kan vi afbøde problemet ved hjælp af test på lavere niveau.

Hvorfor skulle jeg tage disse tests?

Der er to forskellige scenarier, som jeg gerne vil dække:

Den første er at teste dine egne REST API'er. Disse tests tilføjer et ekstra lag af selvtillid. Du bruger helt sikkert en sund blanding af forskellige tests (enhed, integration, funktionel, ...). End-to-end tests kan være den endelige bekræftelse på, at alt ser godt ud.

Den anden sag er at teste API'er, som du ikke kontrollerer. I mine sidste projekter kom de fleste af de data, vi forbrugte, fra API'er, der blev serveret af andre hold. Mere end en gang tilbragte jeg en halv dag med at fejle en fejl i min app, kun for at bemærke, at en downstream API blev borked hele tiden. Automatiske tests dækker denne integration og hjælper med at isolere problemer.

Levende dokumentation

En samling af tests, der udføres regelmæssigt, fungerer som den bedste dokumentation for en API. Har du søgt efter noget i enhver virksomheds wiki for nylig? Hvis du overhovedet finder noget, skal du være glad. Det vil sandsynligvis være ufuldstændigt. Eller bare fladt forkert ud. Sjove tider.

Overvågning

I begge tilfælde kan disse tests skifte fra en gateway i byggeprocessen til et aktivt overvågningsværktøj. Ved konstant at køre dem sørger du for, at API'en stadig fungerer, som du forventer. Ellers hæves de rigtige alarmer. Du ønsker ikke at indse, at der er noget galt, bare når en kunde klager.

Hvorfor ikke bruge forbrugerdrevne kontraktprøver i stedet?

Fantastisk spørgsmål, hvis jeg må sige det selv. CDC'er er en glimrende måde at sikre, at en API overholder det, en klient forventer af den. Hvis du kan konfigurere dem korrekt, vil de erstatte end-to-end-tests næsten fuldstændigt. Husk, fortsæt med at skubbe testene til et lavere niveau, når du kan.

De fungerer dog ikke i enhver situation. Hvis du ikke kontrollerer både udbyderen og forbrugeren, skal du stole på en anden part. Hvis de ikke opfylder deres del af kontrakten, vil testene være ubrugelige. Nogle hold er bare ikke i stand til løbende at køre tests mod en kontrakt. At køre dine egne tests kan være dit bedste valg.

Under alle omstændigheder er det tid til noget kode efter at have lagt grunden .

Oprettelse af en postbudssamling

Samlingen

Vi definerer et antal opkald, der udføres sekventielt inde i vores CI. Hvert opkald udfører en anmodning mod API'en. Derefter kører det nogle tests for at kontrollere, at anmodningen var vellykket, kontrollere statuskoden og kroppen også.

For at oprette samlingen har jeg en tendens til at bruge Postman-appen. Jeg kan godt lide at udtrække ting som URL'er og parametre til et miljø. Derefter bliver det lettere at konfigurere det, og du har ikke nogen følsomme oplysninger i selve samlingen. Din historie er et praktisk sted at begynde at opbygge denne samling.

Når du er tilfreds med samlingen, kan du eksportere den som en JSON-fil. Denne fil kan bruges i kildekontrol for at tjene som en base for den pipeline, der kører testene. Der er en Pro- og Enterprise-version, der hjælper med at administrere samlinger, som jeg ikke rigtig har prøvet. Alligevel er et godt ol- gitlager mere end nok til at komme i gang.

eksportpostmand

Kører samlingen

Indtil nu har vi brugt almindelig postbud og intet andet. Nu er det tid for nybegynder at skinne. Hvad taler jeg om, alligevel? Jeg citerer de officielle dokumenter direkte:

Newman er en kommandolinje Collection Runner for Postman. Det giver dig mulighed for at køre og teste en postbudssamling direkte fra kommandolinjen.

Godt, at vi præciserede det! Det er installeret som en npm-pakke, hvilket kan resultere i en package.jsonså enkel som denne:

{ "name": "postman-utils", "version": "0.0.1", "private": true, "description": "Postman utilities", "scripts": { "newman": "node_modules/.bin/newman run" }, "dependencies": { "newman": "^4.4.1" } } 

som nævnt før, vil du ikke hardcode variabler som URL'er, parametre eller, Gud forbyde, adgangskoder i den samling. Det er ikke fleksibelt, og det er ikke sikkert. I stedet kan jeg godt lide at bruge en konfigurationsfil, der indeholder alle disse værdier. Men hvis vi vil forpligte den fil, er vi stadig nødt til at finde ud af en måde at undgå at lægge hemmeligheder derinde. Jeg bruger det som en skabelon og erstatter værdier ved kørsel med envsubst. Konfigurationsfilen ser sådan ud

{ "id": "425cf4df-d994-4d91-9efb-41eba1ead456", "name": "echo", "values": [ { "key": "host", "value": "${HOST}", "enabled": true } ] } 

Du kan orkestrere dette med et simpelt bash-script. Scriptet injicerer variablerne i skabelonen, kører newman og sletter filerne for at undgå lækager. Det går meget godt med gopass, hvor du sikkert kan gemme dine hemmeligheder og hente dem gennem scriptet.

setup-newman() { settings=/tmp/settings.json.$$ result=/tmp/variables.json.$$ # shellcheck disable=SC2064 trap "rm -f \"$settings\" \"$result\"" EXIT } run-newman() { local service=${1?You need to provide the service to check} envsubst  "$settings" npx newman run "$service.json" \ -e "${settings}" \ --export-environment "${result}" } 

denne hjælper kan kaldes med den samling, du vil teste. Eksporterede variabler vælges af envsubst. npx giver os lidt mere fleksibilitet til at finde den newmanbinære, hvis du ikke vil bruge en, package.jsonmen har den installeret globalt.

goal_check-service() { setup export SERVICE_PASSWORD=${SERVICE_PASSWORD:-$(gopass store/service/password)} run_newman service } 

Test

At stille en anmodning er kun det første skridt. Husk, vi sigter mod at opbygge en testpakke. Vi har en praktisk testfane i Postman, som vi kan bruge til at skrive vores tests.

test-fane

Vores tests er skrevet i JavaScript ved hjælp af Chai. Lad os sige, at jeg vil teste, at mit opkald leverede en liste med resultater, jeg kunne gøre det sådan:

var getResults = function() { var jsonData = pm.response.json(); return jsonData['results']; }; pm.test("Request was successful", function () { pm.response.to.have.status(200); }); pm.test("There are results", function () { pm.expect(getResults().length).to.be.above(0); }); 

Flere detaljer kan findes her

Bygning flyder

All the calls in a collection get executed sequentially. This offers us the opportunity to test whole flows instead of just single calls. One such a flow for a /posts resource is:

  • Get a list of all posts
  • Fetch the first post in the list
  • Update the post

We'll build a suite of parametrized tests that will continue to work over time, not just the first time that you ran it. An important part of this is modifying the environment in a request. That is our way of transmitting parameters between requests. Let's say our first request was successful, as corroborated by our tests. Then we store the id on a variable that will be used to fetch a particular entity.

// First result in the list var post = getResults()[0]; // Pass variables to other stages pm.environment.set("id", post.id) 

The next request can use that parameter as any that we set manually.

Ignoring calls based on a condition

Flows might need also need some logic to skip certain requests. Let's say you have a request that is creating a new entity through a POST. You want to have that request, but you may not want to run it on every commit. Maybe you just want do it once per day. In that case, we'll skip the test based on a certain variable.

// Do not run create request in sequence, unless executeCreate is set to true if(!pm.environment.get("executeCreate")) { postman.setNextRequest('Get other posts') } 

The variable goes into the configuration file, and is set to a environment variable that gets injected through our script, as I showed above.

Time for some continuous integration

At this point you should have a collection that runs locally. Running this once is fine, but why not run it for every commit? Or maybe every hour, if you want to check an API that you don't control?

Your CI pipeline is a perfect place to do this. I'm going to use CircleCI for my example, but any CI will do. I run the tests inside a docker image that I built which includes all the required dependencies. There is an official Docker image provided by Postman already. However, it does not contain envsubst and it uses an older NodeJS version.

The helper script that we built in the step before will work without any changes inside CircleCI. We just have to provide the required secrets as variables. This is the job:

 healthcheck: docker: - image: sirech/newman-executor:12.6 steps: - checkout - run: ./go test-e2e 

which will produce a report similar to this:

produktion

What about the alternatives?

Many frameworks provide their own way of running tests against a running API. In Spring Boot, for instance, you can use MockMvc to test controllers. You can use both, in my view. First the native tests, so to speak, and then layer Postman Tests on top.

And let's not forget about good ol' curl. I had a huge collection of curl commands with which I tested an API that was needed for my last project. However, managing that becomes more and more tedious over time. If you want to use send complex requests, like certificates or cookies, Postman is way more convenient to use. Moreover, you can use JavaScript instead of bash, which can make things a bit easier to read and maintain.

What else?

Dette er allerede en hel del, og det er bare begyndelsen. Alt hvad du laver med en API, kan du også automatisere. For eksempel havde vi i mit tidligere projekt en samling, der kørte en OAuth Flow. Det fik os et symbol, som vi kunne bruge til at stille anmodninger mod et autoriseret slutpunkt.

En repo, der skal bruges som et eksempel

Her er et lager for et Kotlin-program, der kører en Postman-samling som en e2e-test. Det kan tjene som et startsæt til at komme i gang med End-to-End API-tests af høj kvalitet.