HTTP-mock-tester lar deg implementere og teste en funksjon, selv om avhengige tjenester ikke er implementert ennå. Du kan også teste tjenester som allerede er implementert uten at du faktisk ringer disse tjenestene, med andre ord kan du teste dem offline. Du må analysere dine forretningsbehov for det programmet først, og skrive dem som scenarier i designdokumenter.
La oss si at du utvikler en Node.js-klient-API for en medieklient som er en tjeneste (det er ingen slik tjeneste i virkeligheten, bare for testing) for musikk, video, bilder osv. Det vil være mange funksjoner i denne API, og det kan være behov for noen endringer fra tid til annen.
Hvis du ikke har noen tester for denne API-en, vet du ikke hvilke problemer det vil føre til. Hvis du har tester for denne API-en, kan du imidlertid oppdage problemer ved å kjøre alle testene du har skrevet før. Hvis du utvikler en ny funksjon, må du legge til angitte testtilfeller for det. Du finner en API som allerede er implementert i dette GitHub-depotet. Du kan laste ned prosjektet og kjøre npm test
for å kjøre alle testene. La oss fortsette testdelen.
For en HTTP mock test, vil vi bruke nock, som er et HTTP mocking og forventning bibliotek for Node.js. I HTTP mock testing kan du bruke følgende flyt:
La oss tenke på en medieklient-API. La oss si at du ringer til funksjonen musicsList
ved å bruke en forekomst av Media
bibliotek som nedenfor:
var Media = krever ('... / lib / media'); var mediaClient = ny Media ("your_token_here"); mediaClient.musicsList (funksjon (feil, respons) console.logs (respons);)
I dette tilfellet får du en musikkliste i respons
variabel ved å gjøre en forespørsel til https://ap.example.com/musics
inne i denne funksjonen. Hvis du vil skrive for dette, må du tøffe forespørsler for å få testene dine til å kjøre offline. La oss simulere denne forespørselen i nock.
beskrive ('Music Tests', funksjon () it ('should list music', funksjon (ferdig) nock ('https://api.example.com') .get ('/ musics') .reply (200 , 'OK'); mediaClient.musicList (funksjon (feil, svar) forvente (svar) .to.eql ('OK') gjort ())))
Beskriv ('Musikkprøver', funksjon () ...
er for å gruppere tester. I eksempelet ovenfor grupperer vi musikkrelaterte tester under samme gruppe. det ('skal liste musikk', funksjon (ferdig) ...
er for testing av spesifikke handlinger i musikkrelaterte funksjoner. I hver test ferdig
tilbakeringing er gitt for å sjekke testresultatet i tilbakekallingsfunksjonen til den virkelige funksjonen. I mock-forespørselen antar vi at den vil svare OK
hvis vi kaller musicList
funksjon. Det forventede og faktiske resultatet sammenlignes inne i tilbakekallingsfunksjonen.
Du kan definere din forespørsel og svardata i en fil. Du kan se nedenstående eksempel for å samsvare svardata fra en fil.
det ('skal lage musikk og svare som i ressursfil', funksjon (ferdig) nock ('https://api.example.com'). post ('/ musics', title: 'Røyke på vannet' , forfatter: 'Deep Purple', varighet: '5,40 min.') .reply (200, funksjon (uri, requestBody) return fs.createReadStream (path.normalize (__ dirname + '/resources/new_music_response.json' utf8 '))); mediaClient.musicCreate (tittel:' Røk på vannet ', forfatter:' Deep Purple ', varighet:' 5,40 min. ', funksjon (feil, svar) forventer (JSON.parse svar) .musikk.id) .to.eql (3164495) gjort ()))
Når du lager et musikk, må svaret svare til svaret fra filen.
Du kan også kjede en mock forespørsel i ett omfang som nedenfor:
det ('det burde lage musikk og deretter slette', funksjon (ferdig) nock ('https://api.example.com') .post ('/ musics', title: 'Maps', forfatter: 'Maroon5 'varighet:' 5:00 min. ') .reply (200, musikk: id: 3164494, tittel:' Maps ', forfatter:' Maroon5 ', varighet:' 7:00 min. ') .delete ('/ musics /' + 3164494) .reply (200, 'Music deleted') mediaClient.musicCreate (tittel: 'Maps', forfatter: 'Maroon5', varighet: '5:00 min.' (feil, svar) var musicId = JSON.parse (respons) .musikk.id forventer (musicId) .to.eql (3164494) mediaClient.musicDelete (musicId, funksjon (feil, svar) forvente (svar). eql ('Music deleted') gjort ())))
Som du kan se, kan du gjemme musikkopprettelse og -respons først, og deretter slette musikk, og til slutt svaret på andre data.
I medieklienten, Innholdstype: søknad / json
er gitt i forespørselhodene. Du kan teste et bestemt overskrift som dette:
det ('skal gi token i header', funksjon (ferdig) nock ('https://api.example.com', reqheaders: 'Content-Type': 'application / json') .get '/ musics') .ply (200, 'OK') mediaClient.musicList (funksjon (feil, svar) forvente (svar) .to.eql ('OK') ferdig ()))
Når du gjør en forespørsel til https://api.example.com/musics
med en header Innholdstype: søknad / json
, det vil bli oppfanget av Nock HTTP mock ovenfor, og du vil kunne teste det forventede og faktiske resultatet. Du kan også teste svarhodene på samme måte bare ved å angi svarhodet i svardelen:
det ('skal gi spesifikke overskrift som svar', funksjon (ferdig) nock ('https://api.example.com') .get ('/ musics') .reply (200, 'OK', 'Innhold -Type ':' application / json ') mediaClient.musicList (funksjon (feil, svar) forvente (svar) .to.eql (' OK ') gjort ()))
Du kan angi standard svarhoder for forespørslene i ett omfang ved å bruke defaultReplyHeaders
som følger:
den ('skal gi standard respons header', funksjon (ferdig) nock ('https://api.example.com') .defaultReplyHeaders ('Content-Type': 'application / json') .get / music ') .reply (200,' OK, med standard respons headers ') mediaClient.musicList (funksjon (feil, svar) forvente (svar) .to.eql (' OK, med standard respons headers ') ))
Når du ringer til API, finner du standard svarhodene i svaret, selv om det ikke er angitt.
HTTP-operasjoner er grunnleggende for klientforespørsler. Du kan fange opp alle HTTP-operasjoner ved å bruke avskjære
:
omfang ('http://api.example.com') .intercept ('/ musics / 1', 'DELETE') .reply (404);
Når du prøver å slette musikk med ID 1, svarer det på 404. Du kan sammenligne ditt faktiske resultat med 404 for å sjekke teststatusen. Også du kan bruke FÅ
, POST
, SLETT
, LAPP
, SETTE
, og HODE
på samme måten.
Normalt er mock forespørsler gjort ved hjelp av nock tilgjengelig for første gang. Du kan gjøre det tilgjengelig så mye du vil ha slik:
var scope = nock ('https://api.example.com') .get ('/ musics') .times (2) .reply (200, 'OK med musikkliste'); http.get ( 'https://api.example.com/musics'); // "OK med musikkliste" http.get ('https://apiexample.com/musics'); // "OK med musikkliste" http.get ('https://apiexample.com/musics'); // "Virkelig respons fra api"
Du er begrenset til å gjøre to forespørsler som mock HTTP-forespørsler. Når du gjør tre eller flere forespørsler, vil du automatisk lage en reell forespørsel til API.
Du kan også gi en egendefinert port i API-nettadressen din:
det ('skal håndtere spesifikke port', funksjon (ferdig) forespørsel nock ('https://api.example.com:8081') .get ('/') .reply (200, 'OK med tilpasset port') ('https://api.example.com:8081', funksjon (feil, svar, kropp) forventer (kropp) .to.eql ('OK med tilpasset port') gjort ()))
Scope-filtrering blir viktig når du vil filtrere domenet, protokollen og porten for testene dine. For eksempel vil underprøven gi deg mulighet til å henge forespørsler som har underdomener som API0, API1, API2 osv.
den ('skal også støtte underdomener', funksjon (ferdig) nock ('http://api.example.com', filteringScope: funksjon (omfang) return / ^ http: \ / \ / api [0- 9] *. Example.com/.test(scope);) .get ('/ musics') .reply (200, 'OK med dynamisk underdomener') forespørsel ('http://api2.example.com/ musics ', funksjon (feil, respons, kropp) forventer (kropp) .to.eql (' OK med dynamiske underdomener ') gjort ()))
Du er ikke begrenset til en nettadresse her; Du kan teste underdomener som er angitt i regexp
.
Noen ganger kan nettadresseparametrene dine variere. For eksempel er paginasjonsparametrene ikke statiske. I så fall kan du bruke følgende test:
den ('skal støtte dynamisk paginering', funksjon (ferdig) nock ('http://api.example.com') .filtreringPath (/ page = [^ &] * / g, 'page = 123') .get ('/ musics? page = 123') .reply (200, 'Ok respons with paginate') forespørsel ('http://api.example.com/musics?page=13', funksjon (feil, svar, kropp) forvente (kropp) .to.eql ('Ok svar med paginering') ferdig ()))
Hvis du har varierende felt i din forespørsel, kan du bruke filteringRequestBody
å eliminere varierende felt som dette:
det ('skal lage film med dynamisk tittel', funksjon (ferdig) nock ('http://api.example.com') .filteringRequestBody (funksjon (sti) return 'test') .post ('/ musics ',' test ') .reply (201,' OK '); var options = url:' http://api.example.com/musics ', metode:' POST ', body:' author = test_author & title = test ' forespørsel (valg, funksjon (feil, svar, kropp) forventer (kropp) .to.eql (' OK ') gjort ()))
Her forfatter
kan variere, men du kan fange opp forespørselslegemet med title = test
.
I denne klienten brukes et token til å godkjenne klientbrukeren. Du må sjekke overskriften for å se et gyldig token i Autorisasjon
Overskrift:
det ('skal matche bærer token header', funksjon (ferdig) nock ('https://api.example.com') .matchHeader ('Authorization', /Bearer.*/) .get ('/ musics') .comment (200, 'Ok svar med musikkliste') mediaClient.musicList (funksjon (feil, svar) forvente (svar) .to.eql ('OK svar med musikkliste') gjort ()))
I testtilfeller kan du aktivere ekte HTTP-forespørsler ved å sette inn allowUnmocked
som sant. La oss se på følgende tilfelle:
den ('bør be om å utføre "http://api.example.com", funksjon (ferdig) var scope = nock (' http://api.example.com ', allowUnmocked: true) .get ('/ musics') .reply (200, 'OK'); http.get ('http://api.example.com/musics'); // Dette vil bli avlyst av nock http.get ('http: //api.example.com/videos '); // Dette vil gjøre en reell forespørsel til tjeneste)
I et nock-scenario kan du se et scenario for / musikken
URI, men også hvis du gjør noen annonse annerledes enn / musikken
, Det vil være en reell forespørsel til den angitte webadressen i stedet for en feiltest.
Vi har dekket hvordan du skriver scenarier ved å gi en prøveforespørsel, svar, header, etc., og sjekke det faktiske og forventede resultatet. Du kan også bruke noen forventningsverktøy som er ferdig()
, fjern rekkevidde scenariet med cleanAll ()
, bruk et nock-scenario for alltid ved å bruke fortsette()
, og listen i venteproblemer i testet ditt ved å bruke pendingMocks ()
.
La oss si at du har skrevet et nock-scenario og utfører en ekte funksjon til et testscenario. I testfasen kan du sjekke om det skrevne scenariet er utført eller ikke som følger:
det ('bør be om å bli utført til' http://api.example.com '', funksjon (ferdig) var musicList = nock ('http://api.example.com') .get ('/ musics') .reply (200, 'OK med musikkliste'); forespørsel ('http://api.example.com/musics', funksjon (feil, svar) forventer (musicList.isDone ()) .to.eql ) gjort ()))
Innenfor forespørsel tilbakeringing, forventer vi at nettadressen i nock-scenariet (http://api.example.com/musics) skal ringes.
Hvis du bruker et nock-scenario med fortsette()
, Det vil være tilgjengelig for alltid under utførelsen av testen din. Du kan rydde scenariet når du vil, ved å bruke denne kommandoen som vist i følgende eksempel:
den ('skulle mislykkes på grunn av rydding av omfanget', funksjon (ferdig) var musicList = nock ('http://api.example.com') .get ('/ musics') .reply (200, 'OK med musikk liste '); nock.cleanAll (); forespørsel (' http://api.example.com/musics ', funksjon (feil, respons, kropp) forventer (kropp) .not.eql (' OK med musikkliste ' ) gjort ()))
I denne testen samsvarer vår forespørsel og svar med scenariet. Men etterpå nock.cleanAll ()
Vi tilbakestiller scenariet, og vi forventer ikke et resultat med 'OK med musikkliste'
.
Hver nock-scenario er bare tilgjengelig første gang. Hvis du vil gjøre det levende for alltid, kan du bruke en test som denne:
det ('skal være tilgjengelig for uendelig forespørsel', funksjon (ferdig) nock ('http://api.example.com') .get ('/ musics') .reply (200, 'OK') // Først anropsforespørsel ('https://api.example.com/musics', funksjon (feil, svar, kropp) forventer (kropp) .to.eql ('OK') ferdig ()) // Andre anropsforespørsel ( 'https://api.example.com/musics', funksjon (feil, svar, kropp) forventer (kropp) .to.eql ('OK') gjort ()) // ...)
Du kan liste de ventende nock scenariene som ikke er ferdig ennå i testen din som følger:
den ('skal logge på ventende mocks', funksjon (ferdig) var scope = nock ('http://api.example.com') .persist () .get ('/') .reply (200, 'OK' ); hvis (! scope.isDone ()) console.error ('Waiting mocks:% j', scope.pendingMocks ());)
Du vil kanskje også se handlingene som ble utført under testkjøring. Du klarer å gjøre det ved å bruke følgende eksempel:
det ('skal logge alle forespørsler', funksjon (ferdig) var musicList = nock ('http://api.example.com') .log (console.log) .get ('/ musics') .reply ( 200, 'OK med musikkliste'); forespørsel ('http://api.example.com/musics', funksjon (feil, svar, kropp) forventer (kropp) .eql ('OK med musikkliste') ferdig ()))
Denne testen genererer en utgang som vist nedenfor:
som matcher GET http://api.example.com:80/musics for å få http://api.example.com:80/musics: true
Noen ganger må du deaktivere mocking for bestemte nettadresser. For eksempel vil du kanskje ringe den virkelige http://tutsplus.com
, i stedet for den spottede. Du kan bruke:
nock.nock.enableNetConnect ( 'tutsplus.com');
Dette vil gjøre en reell forespørsel inne i testene dine. Du kan også aktivere / deaktivere globalt ved å bruke:
nock.enableNetConnect (); nock.disableNetConnect ();
Vær oppmerksom på at hvis du deaktiverer nettverksforbindelse, og prøver å få tilgang til en uhindret nettadresse, får du en NetConnectNotAllowedError
unntak i testen din.
Det er best praksis å skrive testene dine før virkelig gjennomføring, selv om din avhengige tjeneste ikke er implementert ennå. Utover dette må du kunne teste testene dine når du er offline. Nock lar deg simulere din forespørsel og svar for å teste din søknad.