Sveobuhvatan vodič za integracijsko testiranje s naglaskom na testiranje API-ja pomoću Supertesta, pokrivajući postavljanje, najbolje prakse i napredne tehnike.
Integracijsko testiranje: Ovladavanje testiranjem API-ja pomoću Supertesta
U svijetu razvoja softvera, osiguravanje ispravnog funkcioniranja pojedinačnih komponenti u izolaciji (jedinično testiranje) je ključno. Međutim, jednako je važno provjeriti rade li te komponente besprijekorno zajedno. Tu na scenu stupa integracijsko testiranje. Integracijsko testiranje fokusira se na provjeru interakcije između različitih modula ili servisa unutar aplikacije. Ovaj članak duboko uranja u integracijsko testiranje, s posebnim naglaskom na testiranje API-ja pomoću Supertesta, moćne i jednostavne biblioteke za testiranje HTTP tvrdnji u Node.js-u.
Što je integracijsko testiranje?
Integracijsko testiranje je vrsta testiranja softvera koja kombinira pojedinačne softverske module i testira ih kao grupu. Cilj mu je otkriti nedostatke u interakcijama između integriranih jedinica. Za razliku od jediničnog testiranja, koje se fokusira na pojedinačne komponente, integracijsko testiranje provjerava protok podataka i kontrolni tok između modula. Uobičajeni pristupi integracijskom testiranju uključuju:
- Integracija odozgo prema dolje: Počevši s modulima najviše razine i integrirajući prema dolje.
- Integracija odozdo prema gore: Počevši s modulima najniže razine i integrirajući prema gore.
- Integracija "velikog praska" (Big-bang): Integriranje svih modula istovremeno. Ovaj pristup se općenito manje preporučuje zbog poteškoća u izoliranju problema.
- Sendvič integracija: Kombinacija integracije odozgo prema dolje i odozdo prema gore.
U kontekstu API-ja, integracijsko testiranje uključuje provjeru ispravnog zajedničkog rada različitih API-ja, provjeru dosljednosti podataka koji se prenose između njih te provjeru funkcionira li cjelokupni sustav kako se očekuje. Na primjer, zamislite aplikaciju za e-trgovinu s odvojenim API-jima za upravljanje proizvodima, autentifikaciju korisnika i obradu plaćanja. Integracijsko testiranje osiguralo bi ispravnu komunikaciju tih API-ja, omogućujući korisnicima pregledavanje proizvoda, sigurnu prijavu i dovršetak kupnje.
Zašto je integracijsko testiranje API-ja važno?
Integracijsko testiranje API-ja ključno je iz nekoliko razloga:
- Osigurava pouzdanost sustava: Pomaže u ranom otkrivanju problema s integracijom u razvojnom ciklusu, sprječavajući neočekivane kvarove u produkciji.
- Potvrđuje integritet podataka: Provjerava jesu li podaci ispravno preneseni i transformirani između različitih API-ja.
- Poboljšava performanse aplikacije: Može otkriti uska grla u performansama povezana s interakcijama API-ja.
- Povećava sigurnost: Može identificirati sigurnosne ranjivosti koje proizlaze iz nepravilne integracije API-ja. Na primjer, osiguravanje ispravne autentifikacije i autorizacije prilikom komunikacije API-ja.
- Smanjuje troškove razvoja: Rano rješavanje problema s integracijom znatno je jeftinije od njihovog rješavanja kasnije u razvojnom ciklusu.
Uzmimo za primjer globalnu platformu za rezervaciju putovanja. Integracijsko testiranje API-ja je od presudne važnosti kako bi se osigurala nesmetana komunikacija između API-ja koji obrađuju rezervacije letova, hotelske rezervacije i pristupnike za plaćanje iz različitih zemalja. Neuspješna integracija ovih API-ja mogla bi dovesti do netočnih rezervacija, neuspjeha plaćanja i lošeg korisničkog iskustva, što negativno utječe na ugled i prihod platforme.
Predstavljamo Supertest: Moćan alat za testiranje API-ja
Supertest je apstrakcija visoke razine za testiranje HTTP zahtjeva. Pruža praktičan i tečan API za slanje zahtjeva vašoj aplikaciji i postavljanje tvrdnji o odgovorima. Izgrađen na vrhu Node.js-a, Supertest je posebno dizajniran za testiranje Node.js HTTP poslužitelja. Izvanredno dobro radi s popularnim okvirima za testiranje kao što su Jest i Mocha.
Ključne značajke Supertesta:
- Jednostavan za korištenje: Supertest nudi jednostavan i intuitivan API za slanje HTTP zahtjeva i postavljanje tvrdnji.
- Asinkrono testiranje: Besprijekorno rukuje asinkronim operacijama, što ga čini idealnim za testiranje API-ja koji se oslanjaju na asinkronu logiku.
- Tečno sučelje (Fluent Interface): Pruža tečno sučelje, omogućujući vam lančano povezivanje metoda za sažete i čitljive testove.
- Sveobuhvatna podrška za tvrdnje: Podržava širok raspon tvrdnji za provjeru statusnih kodova odgovora, zaglavlja i tijela.
- Integracija s okvirima za testiranje: Besprijekorno se integrira s popularnim okvirima za testiranje poput Jesta i Moche, omogućujući vam korištenje postojeće infrastrukture za testiranje.
Postavljanje testnog okruženja
Prije nego što počnemo, postavimo osnovno testno okruženje. Pretpostavit ćemo da imate instaliran Node.js i npm (ili yarn). Koristit ćemo Jest kao naš okvir za testiranje i Supertest za testiranje API-ja.
- Kreirajte Node.js projekt:
mkdir api-testing-example
cd api-testing-example
npm init -y
- Instalirajte ovisnosti:
npm install --save-dev jest supertest
npm install express # Ili vaš preferirani okvir za izradu API-ja
- Konfigurirajte Jest: Dodajte sljedeće u svoju
package.json
datoteku:
{
"scripts": {
"test": "jest"
}
}
- Kreirajte jednostavnu API krajnju točku (endpoint): Kreirajte datoteku pod nazivom
app.js
(ili slično) sa sljedećim kodom:
const express = require('express');
const app = express();
const port = 3000;
app.get('/hello', (req, res) => {
res.send('Hello, World!');
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
module.exports = app; // Izvoz za potrebe testiranja
Pisanje prvog Supertest testa
Sada kada smo postavili okruženje, napišimo jednostavan Supertest test kako bismo provjerili našu API krajnju točku. Kreirajte datoteku pod nazivom app.test.js
(ili slično) u korijenu vašeg projekta:
const request = require('supertest');
const app = require('./app');
describe('GET /hello', () => {
it('odgovara sa 200 OK i vraća \"Hello, World!\"', async () => {
const response = await request(app).get('/hello');
expect(response.statusCode).toBe(200);
expect(response.text).toBe('Hello, World!');
});
});
Objašnjenje:
- Uvozimo
supertest
i našu Express aplikaciju. - Koristimo
describe
za grupiranje naših testova. - Koristimo
it
za definiranje specifičnog testnog slučaja. - Koristimo
request(app)
za stvaranje Supertest agenta koji će slati zahtjeve našoj aplikaciji. - Koristimo
.get('/hello')
za slanje GET zahtjeva na/hello
krajnju točku. - Koristimo
await
da bismo pričekali odgovor. Metode Supertesta vraćaju promise, što nam omogućuje korištenje async/await za čišći kod. - Koristimo
expect(response.statusCode).toBe(200)
kako bismo potvrdili da je statusni kod odgovora 200 OK. - Koristimo
expect(response.text).toBe('Hello, World!')
kako bismo potvrdili da je tijelo odgovora "Hello, World!".
Da biste pokrenuli test, izvršite sljedeću naredbu u svom terminalu:
npm test
Ako je sve ispravno postavljeno, trebali biste vidjeti da test prolazi.
Napredne tehnike u Supertestu
Supertest nudi širok raspon značajki za napredno testiranje API-ja. Istražimo neke od njih.
1. Slanje tijela zahtjeva
Za slanje podataka u tijelu zahtjeva, možete koristiti metodu .send()
. Na primjer, kreirajmo krajnju točku koja prihvaća JSON podatke:
app.post('/users', express.json(), (req, res) => {
const { name, email } = req.body;
// Simulacija stvaranja korisnika u bazi podataka
const user = { id: Date.now(), name, email };
res.status(201).json(user);
});
Evo kako možete testirati ovu krajnju točku koristeći Supertest:
describe('POST /users', () => {
it('stvara novog korisnika', async () => {
const userData = {
name: 'John Doe',
email: 'john.doe@example.com',
};
const response = await request(app)
.post('/users')
.send(userData)
.expect(201);
expect(response.body).toHaveProperty('id');
expect(response.body.name).toBe(userData.name);
expect(response.body.email).toBe(userData.email);
});
});
Objašnjenje:
- Koristimo
.post('/users')
za slanje POST zahtjeva na/users
krajnju točku. - Koristimo
.send(userData)
za slanje objektauserData
u tijelu zahtjeva. Supertest automatski postavlja zaglavljeContent-Type
naapplication/json
. - Koristimo
.expect(201)
kako bismo potvrdili da je statusni kod odgovora 201 Created. - Koristimo
expect(response.body).toHaveProperty('id')
kako bismo potvrdili da tijelo odgovora sadrži svojstvoid
. - Koristimo
expect(response.body.name).toBe(userData.name)
iexpect(response.body.email).toBe(userData.email)
kako bismo potvrdili da svojstvaname
iemail
u tijelu odgovora odgovaraju podacima koje smo poslali u zahtjevu.
2. Postavljanje zaglavlja
Za postavljanje prilagođenih zaglavlja u vašim zahtjevima, možete koristiti metodu .set()
. Ovo je korisno za postavljanje autentifikacijskih tokena, vrsta sadržaja ili drugih prilagođenih zaglavlja.
describe('GET /protected', () => {
it('zahtijeva autentifikaciju', async () => {
const response = await request(app).get('/protected').expect(401);
});
it('vraća 200 OK s važećim tokenom', async () => {
// Simulacija dobivanja važećeg tokena
const token = 'valid-token';
const response = await request(app)
.get('/protected')
.set('Authorization', `Bearer ${token}`)
.expect(200);
expect(response.text).toBe('Protected Resource');
});
});
Objašnjenje:
- Koristimo
.set('Authorization', `Bearer ${token}`)
za postavljanje zaglavljaAuthorization
naBearer ${token}
.
3. Rukovanje kolačićima (Cookies)
Supertest također može rukovati kolačićima. Možete postaviti kolačiće koristeći metodu .set('Cookie', ...)
, ili možete koristiti svojstvo .cookies
za pristup i izmjenu kolačića.
4. Testiranje prijenosa datoteka
Supertest se može koristiti za testiranje API krajnjih točaka koje obrađuju prijenos datoteka. Možete koristiti metodu .attach()
za prilaganje datoteka zahtjevu.
5. Korištenje biblioteka za tvrdnje (Chai)
Iako je ugrađena biblioteka za tvrdnje u Jestu dovoljna za mnoge slučajeve, možete koristiti i moćnije biblioteke za tvrdnje poput Chaija sa Supertestom. Chai pruža izražajniju i fleksibilniju sintaksu za tvrdnje. Da biste koristili Chai, trebate ga instalirati:
npm install --save-dev chai
Zatim možete uvesti Chai u svoju testnu datoteku i koristiti njegove tvrdnje:
const request = require('supertest');
const app = require('./app');
const chai = require('chai');
const expect = chai.expect;
describe('GET /hello', () => {
it('odgovara sa 200 OK i vraća \"Hello, World!\"', async () => {
const response = await request(app).get('/hello');
expect(response.statusCode).to.equal(200);
expect(response.text).to.equal('Hello, World!');
});
});
Napomena: Možda ćete trebati konfigurirati Jest da ispravno radi s Chaijem. To često uključuje dodavanje datoteke za postavljanje koja uvozi Chai i konfigurira ga da radi s Jestovim globalnim expect
.
6. Ponovno korištenje agenata
Za testove koji zahtijevaju postavljanje specifičnog okruženja (npr. autentifikacija), često je korisno ponovno koristiti Supertest agenta. Time se izbjegava suvišan kod za postavljanje u svakom testnom slučaju.
describe('Testovi autentificiranog API-ja', () => {
let agent;
beforeAll(() => {
agent = request.agent(app); // Kreiranje postojanog agenta
// Simulacija autentifikacije
return agent
.post('/login')
.send({ username: 'testuser', password: 'password123' });
});
it('može pristupiti zaštićenom resursu', async () => {
const response = await agent.get('/protected').expect(200);
expect(response.text).toBe('Protected Resource');
});
it('može izvršiti druge radnje koje zahtijevaju autentifikaciju', async () => {
// Ovdje izvršite druge autentificirane radnje
});
});
U ovom primjeru, kreiramo Supertest agenta u beforeAll
kuki i autentificiramo agenta. Sljedeći testovi unutar describe
bloka mogu zatim ponovno koristiti ovog autentificiranog agenta bez potrebe za ponovnom autentifikacijom za svaki test.
Najbolje prakse za integracijsko testiranje API-ja pomoću Supertesta
Kako biste osigurali učinkovito integracijsko testiranje API-ja, razmotrite sljedeće najbolje prakse:
- Testirajte cjelovite radne procese (End-to-End Workflows): Usredotočite se na testiranje cjelovitih korisničkih radnih procesa, a ne na izolirane API krajnje točke. To pomaže u identificiranju problema s integracijom koji možda nisu očiti prilikom testiranja pojedinačnih API-ja u izolaciji.
- Koristite realne podatke: Koristite realne podatke u svojim testovima kako biste simulirali stvarne scenarije. To uključuje korištenje valjanih formata podataka, graničnih vrijednosti i potencijalno nevažećih podataka za testiranje rukovanja pogreškama.
- Izolirajte svoje testove: Osigurajte da su vaši testovi neovisni jedni o drugima i da se ne oslanjaju na dijeljeno stanje. To će vaše testove učiniti pouzdanijima i lakšima za otklanjanje pogrešaka. Razmislite o korištenju namjenske testne baze podataka ili o mockanju vanjskih ovisnosti.
- Mockajte vanjske ovisnosti: Koristite mockanje kako biste izolirali svoj API od vanjskih ovisnosti, kao što su baze podataka, API-ji trećih strana ili drugi servisi. To će vaše testove učiniti bržima i pouzdanijima, a također će vam omogućiti testiranje različitih scenarija bez oslanjanja na dostupnost vanjskih servisa. Biblioteke poput
nock
korisne su za mockanje HTTP zahtjeva. - Pišite sveobuhvatne testove: Težite sveobuhvatnoj pokrivenosti testovima, uključujući pozitivne testove (provjera uspješnih odgovora), negativne testove (provjera rukovanja pogreškama) i granične testove (provjera rubnih slučajeva).
- Automatizirajte svoje testove: Integrirajte svoje testove integracije API-ja u svoj cjevovod za kontinuiranu integraciju (CI) kako biste osigurali da se automatski pokreću svaki put kad se naprave promjene u kodu. To će pomoći u ranom identificiranju problema s integracijom i spriječiti njihov dolazak u produkciju.
- Dokumentirajte svoje testove: Jasno i sažeto dokumentirajte svoje testove integracije API-ja. To će drugim programerima olakšati razumijevanje svrhe testova i njihovo održavanje tijekom vremena.
- Koristite varijable okruženja: Pohranjujte osjetljive informacije poput API ključeva, lozinki za baze podataka i drugih konfiguracijskih vrijednosti u varijablama okruženja, umjesto da ih tvrdo kodirate u svojim testovima. To će vaše testove učiniti sigurnijima i lakšima za konfiguriranje za različita okruženja.
- Razmotrite API ugovore: Koristite testiranje API ugovora kako biste potvrdili da se vaš API pridržava definiranog ugovora (npr. OpenAPI/Swagger). To pomaže osigurati kompatibilnost između različitih servisa i sprječava prijelomne promjene. Alati poput Pacta mogu se koristiti za testiranje ugovora.
Uobičajene pogreške koje treba izbjegavati
- Neizoliranje testova: Testovi bi trebali biti neovisni. Izbjegavajte oslanjanje na ishod drugih testova.
- Testiranje detalja implementacije: Usredotočite se na ponašanje i ugovor API-ja, a ne na njegovu internu implementaciju.
- Ignoriranje rukovanja pogreškama: Temeljito testirajte kako vaš API rukuje nevažećim unosima, rubnim slučajevima i neočekivanim pogreškama.
- Preskakanje testiranja autentifikacije i autorizacije: Osigurajte da su sigurnosni mehanizmi vašeg API-ja pravilno testirani kako bi se spriječio neovlašteni pristup.
Zaključak
Integracijsko testiranje API-ja ključan je dio procesa razvoja softvera. Korištenjem Supertesta možete jednostavno pisati sveobuhvatne i pouzdane testove integracije API-ja koji pomažu osigurati kvalitetu i stabilnost vaše aplikacije. Ne zaboravite se usredotočiti na testiranje cjelovitih radnih procesa, korištenje realnih podataka, izoliranje testova i automatizaciju procesa testiranja. Slijedeći ove najbolje prakse, možete značajno smanjiti rizik od problema s integracijom i isporučiti robusniji i pouzdaniji proizvod.
Kako API-ji nastavljaju pokretati moderne aplikacije i arhitekture mikroservisa, važnost robusnog testiranja API-ja, a posebno integracijskog testiranja, samo će rasti. Supertest pruža moćan i pristupačan skup alata za programere diljem svijeta kako bi osigurali pouzdanost i kvalitetu svojih API interakcija.