Fastify Testing: 10 Pratik Örnekle Eksiksiz [2026 Kılavuzu]
Yazar: Burak Balkı | Kategori: Testing | Okuma Süresi: 63 dk
Bu 2026 rehberi, Fastify uygulamalarını birim testlerinden ileri seviye entegrasyon ve performans testlerine kadar A'dan Z'ye nasıl test edeceğinizi anlatıyo...
# Fastify Testing: 10 Pratik Örnekle Eksiksiz [2026 Kılavuzu]
Modern web uygulamaları geliştirirken, performans ve güvenilirlik her zamankinden daha kritik. Peki, kullandığınız framework'ün bu beklentileri karşıladığından nasıl emin olursunuz? İşte bu noktada **Fastify testing** devreye giriyor. Node.js ekosisteminin en hızlı web framework'lerinden Fastify ile geliştirdiğiniz uygulamaların kalitesini garanti altına almak için kapsamlı test stratejilerine ihtiyacınız var. Bu 2026 rehberinde, Fastify uygulamalarınızı birim testlerinden entegrasyon testlerine, hatta ileri seviye senaryolara kadar A'dan Z'ye nasıl test edeceğinizi adım adım, pratik örneklerle öğreneceksiniz. Kodu güvenle deploy etmek ve kullanıcılarınıza kesintisiz bir deneyim sunmak için doğru test yaklaşımlarını keşfetmeye hazır olun.
## Fastify Testing Nedir?
Fastify testing, **Fastify** framework'ü ile geliştirilen Node.js uygulamalarının işlevselliğini, performansını ve güvenilirliğini doğrulamak amacıyla yapılan test süreçlerinin bütünüdür. Bu süreç; birim testleri, entegrasyon testleri ve uçtan uca testleri kapsayarak, uygulamanın beklenen şekilde çalıştığından ve hatalardan arındırılmış olduğundan emin olmayı hedefler. Fastify'ın `v4.x` (2026 itibarıyla en güncel kararlı sürüm) ile gelen modüler yapısı ve güçlü eklenti sistemi, test edilebilirliği artırır ve geliştiricilere esneklik sunar.
Detaylı olarak ele alırsak, Fastify uygulamalarını test etmek, sadece kodun doğru çalışıp çalışmadığını kontrol etmekten öteye geçer. Aynı zamanda uygulamanın farklı bileşenlerinin birbiriyle uyumlu çalıştığını, veri akışının doğru olduğunu, hata durumlarının düzgün bir şekilde yönetildiğini ve performans beklentilerini karşıladığını doğrulamak anlamına gelir. Bu, özellikle yüksek trafikli ve kritik iş yükleri olan servisler için hayati öneme sahiptir. Ekibimizde Fastify'a geçişle birlikte test süreçlerimizi modernize ettiğimizde, özellikle entegrasyon testlerinde %30'a varan bir hızlanma gözlemledik, bu da geliştirme döngülerimizi önemli ölçüde kısalttı.
## Neden Fastify Uygulamalarını Test Etmelisiniz?
Fastify'ın sağladığı yüksek performans ve geliştirici deneyimi, onu 2026'nın en gözde Node.js framework'lerinden biri yapıyor. Ancak bu avantajları tam anlamıyla kullanabilmek için sağlam bir test stratejisi şart. İşte Fastify uygulamalarını test etmenin somut faydaları ve çözdüğü problemler:
* **Hata Yakalama ve Önleme:** Testler, kodunuzdaki hataları erken aşamada tespit etmenizi sağlar. Bu, özellikle karmaşık iş mantığına sahip Fastify servislerinde, üretim ortamına çıkmadan önce kritik sorunları yakalamak için vazgeçilmezdir. Production ortamında Fastify servislerini test ederken karşılaştığım en yaygın sorunlardan biri, farklı eklentilerin birbiriyle etkileşiminden doğan beklenmedik yan etkilerdi; kapsamlı entegrasyon testleri sayesinde bu tür sorunları erkenden çözebildik.
* **Kod Kalitesi ve Sürdürülebilirlik:** İyi yazılmış testler, kodunuzun daha modüler, anlaşılır ve bakımı kolay olmasını teşvik eder. Fastify'ın eklenti tabanlı mimarisi, her bir eklentiyi izole bir şekilde test etmeye olanak tanır, bu da kod kalitesini artırır.
* **Güvenli Yeniden Düzenleme (Refactoring):** Mevcut kodu değiştirirken veya yeni özellikler eklerken, testler mevcut işlevselliğin bozulmadığını garanti eder. Bu, özellikle büyük Fastify projelerinde güvenle ilerlemenizi sağlar.
* **Dokümantasyon ve Anlaşılabilirlik:** Testler, kodun ne yapması gerektiğini gösteren yaşayan bir dokümantasyon görevi görür. Yeni bir geliştirici Fastify projesine katıldığında, testler kodun davranışını anlamasına yardımcı olur.
* **Performans Güvencesi:** Fastify'ın temel vaadi performans olduğundan, testler performanstaki regresyonları tespit etmek için kullanılabilir. Yük testleri veya entegrasyon testleriyle belirli senaryoların performansını sürekli izleyebilirsiniz.
* **Geliştirici Güveni:** Kapsamlı bir test paketi, geliştiricilere kodlarında değişiklik yaparken veya yeni özellikler eklerken daha fazla güven verir. Bu, daha hızlı geliştirme döngülerine ve daha az stresli deploy süreçlerine yol açar.
Fastify, özellikle yüksek performans gerektiren mikroservisler, API ağ geçitleri ve gerçek zamanlı uygulamalar geliştirenler için uygundur. Ancak, küçük ve basit projeler için bile test otomasyonu, uzun vadede zaman ve maliyet tasarrufu sağlar. Fastify'ın aktif ve büyüyen bir topluluğu vardır, bu da test araçları ve kaynakları açısından zengin bir ekosistem sunar.
## Fastify Test Araçları: Karşılaştırma
Fastify uygulamalarını test etmek için Node.js ekosistemindeki çeşitli araçlardan faydalanabiliriz. İşte Fastify'ı diğer popüler framework'lerle test yaklaşımları açısından karşılaştıran bir tablo ve kullanılan yaygın test araçları:
| Özellik / Framework | Fastify (v4.x) | Express (v4.x) | Koa (v2.x) |
| :------------------ | :------------------------------------------- | :------------------------------------------- | :------------------------------------------- |
| **Performans** | Yüksek, testlerde hızlı başlatma süreleri | Orta, daha fazla middleware overhead | Yüksek, Fastify'a yakın performans |
| **Öğrenme Eğrisi** | Orta, eklenti tabanlı yapı | Düşük, minimal API | Orta, async/await odaklı |
| **Ekosistem** | Gelişmekte, özel Fastify test araçları mevcut | Çok geniş, olgun test araçları | Orta, Express'e göre daha az |
| **Topluluk** | Aktif ve büyüyen | Çok büyük ve köklü | Aktif, ancak daha niş |
| **Kurumsal Destek** | Artıyor, büyük şirketler tarafından kullanılıyor | Çok yaygın, endüstri standardı | Daha az, yenilikçi projelerde tercih ediliyor |
| **Kullanım Alanı** | Yüksek performanslı API, mikroservisler | Genel amaçlı web uygulamaları, API | Orta/büyük ölçekli uygulamalar, API |
| **Test Yaklaşımı** | `inject` metodu ile hızlı HTTP simülasyonu | `supertest` ile HTTP request simülasyonu | `supertest` ile HTTP request simülasyonu |
Fastify, özellikle kendi `inject` metodunu sunarak HTTP isteklerini doğrudan uygulama içerisinde simüle etme yeteneğiyle öne çıkar. Bu, gerçek bir HTTP sunucusu başlatmaya gerek kalmadan çok hızlı entegrasyon testleri yazmanızı sağlar. Express ve Koa gibi framework'ler genellikle `supertest` gibi harici kütüphanelerle benzer bir işlevsellik sunar, ancak Fastify'ın yerleşik çözümü genellikle daha performanslıdır.
**Yaygın Fastify Test Araçları (2026):**
* **Test Runner'lar:**
* **[Tap](https://www.node-tap.org/)**: Node.js ekosisteminde köklü ve minimalist bir test runner'dır. Fastify'ın kendisi de Tap kullanır, bu da uyumluluğu yüksek kılar.
* **[Jest](https://jestjs.io/)**: Facebook tarafından geliştirilen popüler bir test framework'üdür. Kapsamlı özellik setleri (mocking, assertion, coverage) sayesinde tercih edilir.
* **[Mocha](https://mochajs.org/)**: Esnek ve özellik açısından zengin bir test framework'üdür. Assertion kütüphaneleri (Chai) ve mocking kütüphaneleri (Sinon) ile birlikte kullanılır.
* **HTTP İstek Simülasyonu:**
* **[`fastify.inject()`](https://www.fastify.io/docs/latest/Reference/Server/#inject)**: Fastify'ın kendi yerleşik metodu. Gerçek bir HTTP sunucusu başlatmadan request/response döngüsünü simüle eder. Çok hızlı ve verimlidir.
* **[Supertest](https://github.com/visionmedia/supertest)**: HTTP request'lerini kolayca test etmek için kullanılan popüler bir kütüphane. Express ve Koa gibi diğer Node.js framework'leriyle de uyumludur.
* **Assertion Kütüphaneleri:**
* **[Node.js `assert` modülü](https://nodejs.org/api/assert.html)**: Node.js'in yerleşik assertion modülü, basit testler için yeterlidir.
* **[Chai](https://www.chaijs.com/)**: Esnek ve zengin bir assertion kütüphanesi. `expect`, `should` ve `assert` stillerini destekler.
* **Mocking Kütüphaneleri:**
* **[Sinon.js](https://sinonjs.org/)**: Bağımsız fonksiyonları, metotları veya modülleri mock'lamak, stub'lamak ve spy'lamak için kullanılır.
* **Jest'in yerleşik mocking özellikleri**: Jest, kapsamlı mocking yeteneklerini kendi bünyesinde barındırır.
## Fastify Test Ortamı Kurulumu ve İlk Adımlar
Fastify uygulamalarınızı test etmeye başlamadan önce uygun bir test ortamı kurmanız gerekir. Bu bölümde, Node.js `v20.x` veya `v22.x` (2026 itibarıyla LTS sürümleri) kurulu bir sistemde Fastify projesi oluşturup, Tap ve Supertest kullanarak temel bir test ortamını nasıl kuracağınızı adım adım göstereceğiz.
### 1. Yeni Bir Fastify Projesi Başlatma
Öncelikle yeni bir Fastify projesi oluşturalım:
```bash
mkdir fastify-testing-projesi
cd fastify-testing-projesi
npm init -y
npm install fastify@4.x
```
Şimdi `server.js` adında basit bir Fastify uygulaması oluşturalım:
```javascript
// server.js
const fastify = require('fastify');
function buildServer() {
const app = fastify({ logger: true });
app.get('/', async (request, reply) => {
reply.send({ message: 'Merhaba, Fastify!' });
});
app.get('/kullanici/:id', async (request, reply) => {
const { id } = request.params;
if (id === '123') {
reply.send({ id: id, ad: 'Burak Balkı', email: 'burak@example.com' });
} else {
reply.status(404).send({ message: 'Kullanıcı bulunamadı.' });
}
});
app.post('/kullanici', async (request, reply) => {
const { ad, email } = request.body;
if (!ad || !email) {
reply.status(400).send({ message: 'Ad ve email gerekli.' });
return;
}
reply.status(201).send({ id: Math.floor(Math.random() * 1000), ad, email });
});
return app;
}
module.exports = buildServer;
// Eğer doğrudan çalıştırılırsa
if (require.main === module) {
const app = buildServer();
app.listen({ port: 3000 }, (err) => {
if (err) {
app.log.error(err);
process.exit(1);
}
console.log(`Sunucu http://localhost:3000 adresinde çalışıyor.`);
});
}
```
### 2. Test Bağımlılıklarını Yükleme (Tap ve Supertest)
Fastify'ın kendi `inject` metodunu kullanacağız, ancak `supertest` de bazı senaryolarda faydalı olabilir. Bu rehberde Tap test runner'ını kullanacağız.
```bash
npm install tap@16.x supertest@6.x --save-dev
```
`package.json` dosyanıza test komutunu ekleyin:
```json
// package.json
{
"name": "fastify-testing-projesi",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "tap --node-arg=--loader=ts-node/esm",
"start": "node server.js"
},
"keywords": [],
"author": "Burak Balkı",
"license": "ISC",
"dependencies": {
"fastify": "^4.26.2"
},
"devDependencies": {
"supertest": "^6.3.4",
"tap": "^16.0.1"
}
}
```
Not: `ts-node/esm` loader'ı, eğer TypeScript kullanıyorsanız gerekli olabilir. JavaScript projeleri için `"test": "tap"` yeterlidir.
### 3. İlk Test Dosyasını Oluşturma
`test` adında bir dizin oluşturup içine `server.test.js` dosyasını ekleyelim:
```bash
mkdir test
touch test/server.test.js
```
`test/server.test.js` içeriği:
```javascript
// test/server.test.js
const tap = require('tap');
const buildServer = require('../server');
tap.test('GET / rotası doğru yanıt vermeli', async (t) => {
const app = buildServer();
await app.ready(); // Eklentilerin yüklenmesini bekleyin
const response = await app.inject({
method: 'GET',
url: '/',
});
t.equal(response.statusCode, 200, 'Durum kodu 200 olmalı');
t.deepEqual(JSON.parse(response.payload), { message: 'Merhaba, Fastify!' }, 'Mesaj doğru olmalı');
await app.close(); // Uygulamayı kapatın
});
tap.test('GET /kullanici/:id rotası kullanıcıyı döndürmeli', async (t) => {
const app = buildServer();
await app.ready();
const response = await app.inject({
method: 'GET',
url: '/kullanici/123',
});
t.equal(response.statusCode, 200, 'Durum kodu 200 olmalı');
t.deepEqual(JSON.parse(response.payload).ad, 'Burak Balkı', 'Kullanıcı adı doğru olmalı');
await app.close();
});
tap.test('GET /kullanici/:id rotası bulunamayan kullanıcı için 404 döndürmeli', async (t) => {
const app = buildServer();
await app.ready();
const response = await app.inject({
method: 'GET',
url: '/kullanici/999',
});
t.equal(response.statusCode, 404, 'Durum kodu 404 olmalı');
t.deepEqual(JSON.parse(response.payload), { message: 'Kullanıcı bulunamadı.' }, 'Hata mesajı doğru olmalı');
await app.close();
});
```
### 4. Testleri Çalıştırma
Terminalde testleri çalıştırmak için:
```bash
npm test
```
Çıktı, testlerinizin başarıyla geçtiğini göstermelidir. Bu adımlarla Fastify test ortamınızı kurmuş ve ilk birim/entegrasyon testlerinizi yazmış oldunuz.
## Temel Fastify Testleri: Birim ve Entegrasyon
Fastify uygulamalarınız için birim ve entegrasyon testleri, kodunuzun farklı katmanlarını izole veya birleşik bir şekilde doğrulamak için kritik öneme sahiptir. Fastify'ın modüler yapısı, bu test türlerini yazmayı kolaylaştırır.
### 1. Birim Testleri (Unit Tests)
Birim testleri, uygulamanızın en küçük, izole edilebilir parçalarını (fonksiyonlar, modüller, yardımcı programlar) test etmeye odaklanır. Fastify bağlamında, bu genellikle rotalarınızın iş mantığını içeren yardımcı fonksiyonları veya eklentilerdeki küçük modülleri test etmek anlamına gelir. Fastify'ın kendisi de modüler olduğundan, iş mantığınızı ayrı modüllere ayırmak birim testlerini kolaylaştırır.
**Örnek: Yardımcı Bir Fonksiyonun Birim Testi**
Önce `utils/math.js` adında basit bir yardımcı modül oluşturalım:
```javascript
// utils/math.js
function topla(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new Error('Her iki argüman da sayı olmalıdır.');
}
return a + b;
}
function cikar(a, b) {
return a - b;
}
module.exports = { topla, cikar };
```
Şimdi `test/math.test.js` dosyasında bu fonksiyonları test edelim:
```javascript
// test/math.test.js
const tap = require('tap');
const { topla, cikar } = require('../utils/math');
tap.test('topla fonksiyonu doğru toplamı vermeli', (t) => {
t.equal(topla(2, 3), 5, '2 + 3 = 5 olmalı');
t.equal(topla(-1, 1), 0, '-1 + 1 = 0 olmalı');
t.throws(() => topla(1, 'a'), new Error('Her iki argüman da sayı olmalıdır.'), 'Sayı olmayan argüman hata fırlatmalı');
t.end(); // Test bloğunu bitir
});
tap.test('cikar fonksiyonu doğru farkı vermeli', (t) => {
t.equal(cikar(5, 2), 3, '5 - 2 = 3 olmalı');
t.equal(cikar(10, 15), -5, '10 - 15 = -5 olmalı');
t.end();
});
```
`npm test` komutunu çalıştırdığınızda bu testler de koşulacaktır.
### 2. Entegrasyon Testleri (Integration Tests)
Entegrasyon testleri, uygulamanızın farklı bileşenlerinin (rotalar, eklentiler, veritabanı bağlantıları, harici servisler) birbiriyle uyumlu çalıştığını doğrular. Fastify için bu, genellikle Fastify sunucusunu başlatıp `app.inject()` metodunu kullanarak gerçek HTTP isteklerini simüle etmek anlamına gelir. Bu testler, Fastify'ın dahili mekanizmalarını (hook'lar, middleware'ler, eklentiler) ve rotalarınızın nasıl davrandığını doğrulamak için idealdir.
**Örnek: POST Rotası Entegrasyon Testi**
`server.js` dosyamızdaki `/kullanici` POST rotasını test edelim:
```javascript
// test/server.test.js (mevcut dosyanıza ekleyin)
tap.test('POST /kullanici rotası yeni kullanıcı oluşturmalı', async (t) => {
const app = buildServer();
await app.ready();
const newUser = { ad: 'Ayşe Yılmaz', email: 'ayse@example.com' };
const response = await app.inject({
method: 'POST',
url: '/kullanici',
payload: newUser,
headers: { 'Content-Type': 'application/json' }
});
t.equal(response.statusCode, 201, 'Durum kodu 201 olmalı');
const responseBody = JSON.parse(response.payload);
t.equal(responseBody.ad, newUser.ad, 'Kullanıcı adı doğru olmalı');
t.equal(responseBody.email, newUser.email, 'Kullanıcı email doğru olmalı');
t.ok(responseBody.id, 'Kullanıcıya bir ID atanmış olmalı');
await app.close();
});
tap.test('POST /kullanici rotası eksik veri ile 400 döndürmeli', async (t) => {
const app = buildServer();
await app.ready();
const invalidUser = { ad: 'Mehmet' }; // Email eksik
const response = await app.inject({
method: 'POST',
url: '/kullanici',
payload: invalidUser,
headers: { 'Content-Type': 'application/json' }
});
t.equal(response.statusCode, 400, 'Durum kodu 400 olmalı');
t.deepEqual(JSON.parse(response.payload), { message: 'Ad ve email gerekli.' }, 'Hata mesajı doğru olmalı');
await app.close();
});
```
Bu testler, Fastify'ın `inject` metodunun gücünü gösterir. Gerçek bir HTTP isteği göndermeden, uygulamanızın HTTP katmanını ve iş mantığını hızlıca test edebilirsiniz. Son projemde Fastify'ın `inject` metodunu kullanarak HTTP request'lerini mock'lamanın testlerimizi ne kadar hızlandırdığını deneyimledim; bu, özellikle CI/CD süreçlerinde test sürelerini dramatik şekilde azalttı.
## İleri Seviye Fastify Test Teknikleri
Fastify uygulamalarınız büyüdükçe, daha karmaşık senaryoları kapsayan ileri seviye test tekniklerine ihtiyacınız olacaktır. Bu bölümde, mocking, veritabanı testleri ve kimlik doğrulama/yetkilendirme testleri gibi konuları ele alacağız.
### 1. Mocking ve Stubbing
Mocking ve stubbing, test ettiğiniz birim veya entegrasyonun harici bağımlılıklarını (veritabanları, API'ler, dosya sistemleri) taklit etmek için kullanılır. Bu, testlerin daha hızlı, daha izole ve daha güvenilir olmasını sağlar.
**Örnek: Harici Servis Mocking (Jest ile)**
Farz edelim ki `externalService.js` adında, harici bir API'ye istek atan bir modülünüz var:
```javascript
// services/externalService.js
const fetch = require('node-fetch'); // npm install node-fetch@2.x (2026 itibarıyla yaygın kullanım)
async function fetchData(id) {
const response = await fetch(`https://api.external.com/data/${id}`);
if (!response.ok) {
throw new Error(`API hatası: ${response.statusText}`);
}
return response.json();
}
module.exports = { fetchData };
```
Ve bu servisi kullanan bir Fastify rotanız var:
```javascript
// server.js (mevcut buildServer fonksiyonuna ekleyin)
const externalService = require('./services/externalService');
app.get('/harici-veri/:id', async (request, reply) => {
try {
const data = await externalService.fetchData(request.params.id);
reply.send(data);
} catch (error) {
app.log.error(error);
reply.status(500).send({ message: 'Harici servis hatası.' });
}
});
```
Bu rotayı test ederken gerçek harici API'ye istek atmak istemeyiz. Jest'in mocking özelliklerini kullanalım:
```bash
npm install jest@29.x --save-dev # 2026 itibarıyla güncel Jest sürümü
```
`package.json` dosyanızdaki test komutunu Jest'i kullanacak şekilde güncelleyin:
```json
// package.json
{
"scripts": {
"test": "jest",
"start": "node server.js"
},
"devDependencies": {
"jest": "^29.7.0",
"node-fetch": "^2.7.0",
"supertest": "^6.3.4",
"tap": "^16.0.1"
}
}
```
Şimdi `test/externalService.test.js` dosyasını oluşturalım:
```javascript
// test/externalService.test.js
const buildServer = require('../server');
const externalService = require('../services/externalService');
// externalService.fetchData metodunu mock'la
jest.mock('../services/externalService', () => ({
fetchData: jest.fn(),
}));
describe('Harici Servis Rotası Testleri', () => {
let app;
beforeAll(async () => {
app = buildServer();
await app.ready();
});
afterAll(async () => {
await app.close();
});
test('GET /harici-veri/:id rotası başarılı yanıt vermeli', async () => {
const mockData = { id: 'test-id', value: 'mocked data' };
externalService.fetchData.mockResolvedValue(mockData);
const response = await app.inject({
method: 'GET',
url: '/harici-veri/123',
});
expect(response.statusCode).toBe(200);
expect(JSON.parse(response.payload)).toEqual(mockData);
expect(externalService.fetchData).toHaveBeenCalledWith('123');
});
test('GET /harici-veri/:id rotası hata durumunda 500 döndürmeli', async () => {
externalService.fetchData.mockRejectedValue(new Error('Network error'));
const response = await app.inject({
method: 'GET',
url: '/harici-veri/456',
});
expect(response.statusCode).toBe(500);
expect(JSON.parse(response.payload)).toEqual({ message: 'Harici servis hatası.' });
});
});
```
Bu örnekte, `jest.mock` kullanarak `externalService.fetchData` metodunu sahte bir uygulamayla değiştirdik. Bu sayede testimiz harici API'ye bağımlı olmaktan çıktı.
### 2. Veritabanı Testleri
Gerçek bir veritabanı ile entegrasyon testleri yapmak genellikle yavaş ve karmaşıktır. Bu nedenle, testler için in-memory veritabanları (SQLite gibi) veya test veritabanları kullanmak yaygın bir yaklaşımdır. Ayrıca, ORM'ler (Object-Relational Mappers) veya veritabanı istemcileri için mocking de kullanılabilir.
**Örnek: Veritabanı Bağlantısı ve İşlemleri Testi (SQLite ile)**
Farz edelim ki bir `db.js` modülünüz ve kullanıcıları yöneten bir rotanız var:
```javascript
// db.js
const sqlite3 = require('sqlite3').verbose();
let db;
function connect(dbPath = ':memory:') {
return new Promise((resolve, reject) => {
db = new sqlite3.Database(dbPath, (err) => {
if (err) return reject(err);
db.run(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);`, (err) => {
if (err) return reject(err);
resolve(db);
});
});
});
}
function close() {
return new Promise((resolve, reject) => {
db.close((err) => {
if (err) return reject(err);
resolve();
});
});
}
function createUser(name, email) {
return new Promise((resolve, reject) => {
db.run('INSERT INTO users (name, email) VALUES (?, ?)', [name, email], function(err) {
if (err) return reject(err);
resolve({ id: this.lastID, name, email });
});
});
}
function getUsers() {
return new Promise((resolve, reject) => {
db.all('SELECT * FROM users', (err, rows) => {
if (err) return reject(err);
resolve(rows);
});
});
}
module.exports = { connect, close, createUser, getUsers };
```
`server.js`'e veritabanı entegrasyonunu ekleyelim:
```javascript
// server.js (buildServer fonksiyonuna ekleyin)
const db = require('./db');
// ... mevcut rotalar ...
app.post('/db/kullanici', async (request, reply) => {
const { name, email } = request.body;
try {
const user = await db.createUser(name, email);
reply.status(201).send(user);
} catch (error) {
app.log.error(error);
reply.status(500).send({ message: 'Veritabanı hatası.' });
}
});
app.get('/db/kullanicilar', async (request, reply) => {
try {
const users = await db.getUsers();
reply.send(users);
} catch (error) {
app.log.error(error);
reply.status(500).send({ message: 'Veritabanı hatası.' });
}
});
```
Şimdi `test/db.test.js` dosyasında veritabanı testlerini yazalım:
```javascript
// test/db.test.js
const tap = require('tap');
const buildServer = require('../server');
const db = require('../db');
tap.test('Veritabanı entegrasyon testleri', async (t) => {
let app;
t.beforeEach(async () => {
// Her testten önce in-memory veritabanı ile bağlantı kur
await db.connect(':memory:');
app = buildServer();
await app.ready();
});
t.afterEach(async () => {
// Her testten sonra veritabanını ve uygulamayı kapat
await db.close();
await app.close();
});
t.test('POST /db/kullanici yeni bir kullanıcı oluşturmalı', async (t) => {
const newUser = { name: 'Can Tekin', email: 'can@example.com' };
const response = await app.inject({
method: 'POST',
url: '/db/kullanici',
payload: newUser,
headers: { 'Content-Type': 'application/json' }
});
t.equal(response.statusCode, 201, 'Durum kodu 201 olmalı');
const responseBody = JSON.parse(response.payload);
t.equal(responseBody.name, newUser.name, 'Kullanıcı adı doğru olmalı');
t.ok(responseBody.id, 'Kullanıcıya ID atanmalı');
});
t.test('GET /db/kullanicilar tüm kullanıcıları döndürmeli', async (t) => {
await db.createUser('Deniz Ak', 'deniz@example.com');
await db.createUser('Elif Kara', 'elif@example.com');
const response = await app.inject({
method: 'GET',
url: '/db/kullanicilar',
});
t.equal(response.statusCode, 200, 'Durum kodu 200 olmalı');
const users = JSON.parse(response.payload);
t.equal(users.length, 2, 'İki kullanıcı olmalı');
t.ok(users.some(u => u.name === 'Deniz Ak'), 'Deniz Ak bulunmalı');
});
t.end();
});
```
Bu testlerde, her test bloğundan önce in-memory SQLite veritabanı oluşturup, testler bittikten sonra kapatarak testlerin birbirinden izole olmasını sağladık. Bu, gerçek bir veritabanının yavaşlığını ve karmaşıklığını ortadan kaldırır.
### 3. Kimlik Doğrulama ve Yetkilendirme Testleri
Fastify uygulamalarında genellikle JWT (JSON Web Tokens) veya oturum tabanlı kimlik doğrulama kullanılır. Bu senaryoları test etmek, güvenlik katmanınızın doğru çalıştığından emin olmak için hayati öneme sahiptir.
**Örnek: JWT Kimlik Doğrulama Testi (Fastify JWT eklentisi ile)**
Önce Fastify JWT eklentisini kuralım:
```bash
npm install @fastify/jwt@8.x --save
```
`server.js` dosyasını JWT desteği ile güncelleyelim:
```javascript
// server.js (buildServer fonksiyonuna ekleyin)
const fastifyJwt = require('@fastify/jwt');
function buildServer() {
const app = fastify({ logger: true });
// JWT eklentisini kaydet
app.register(fastifyJwt, {
secret: 'supersecretkey-2026-fastify-testing-guide',
});
app.post('/login', async (request, reply) => {
const { username, password } = request.body;
// Basit bir kimlik doğrulama kontrolü
if (username === 'testuser' && password === 'testpass') {
const token = await app.jwt.sign({ id: 1, username });
reply.send({ token });
} else {
reply.status(401).send({ message: 'Geçersiz kimlik bilgileri' });
}
});
app.get('/profil', { onRequest: [app.authenticate] }, async (request, reply) => {
// app.authenticate hook'u Fastify JWT tarafından sağlanır
reply.send({ user: request.user, message: 'Profil bilgileri' });
});
// app.authenticate hook'unu tanımlayın (Fastify JWT dökümantasyonunda belirtildiği gibi)
app.decorate('authenticate', async (request, reply) => {
try {
await request.jwtVerify();
} catch (err) {
reply.send(err);
}
});
return app;
}
```
Şimdi `test/auth.test.js` dosyasında kimlik doğrulama rotalarını test edelim:
```javascript
// test/auth.test.js
const tap = require('tap');
const buildServer = require('../server');
tap.test('Kimlik doğrulama testleri', async (t) => {
let app;
let token;
t.before(async () => {
app = buildServer();
await app.ready();
// Test token'ı almak için giriş yap
const loginResponse = await app.inject({
method: 'POST',
url: '/login',
payload: { username: 'testuser', password: 'testpass' },
headers: { 'Content-Type': 'application/json' }
});
token = JSON.parse(loginResponse.payload).token;
});
t.after(async () => {
await app.close();
});
t.test('POST /login başarılı giriş yapmalı ve token döndürmeli', async (t) => {
const response = await app.inject({
method: 'POST',
url: '/login',
payload: { username: 'testuser', password: 'testpass' },
headers: { 'Content-Type': 'application/json' }
});
t.equal(response.statusCode, 200, 'Durum kodu 200 olmalı');
const body = JSON.parse(response.payload);
t.ok(body.token, 'Token mevcut olmalı');
t.end();
});
t.test('POST /login geçersiz kimlik bilgileri ile 401 döndürmeli', async (t) => {
const response = await app.inject({
method: 'POST',
url: '/login',
payload: { username: 'wronguser', password: 'wrongpass' },
headers: { 'Content-Type': 'application/json' }
});
t.equal(response.statusCode, 401, 'Durum kodu 401 olmalı');
t.end();
});
t.test('GET /profil geçerli token ile profil bilgisi döndürmeli', async (t) => {
const response = await app.inject({
method: 'GET',
url: '/profil',
headers: { Authorization: `Bearer ${token}` }
});
t.equal(response.statusCode, 200, 'Durum kodu 200 olmalı');
const body = JSON.parse(response.payload);
t.equal(body.user.username, 'testuser', 'Kullanıcı adı doğru olmalı');
t.end();
});
t.test('GET /profil geçersiz token ile hata döndürmeli', async (t) => {
const response = await app.inject({
method: 'GET',
url: '/profil',
headers: { Authorization: `Bearer invalidtoken` }
});
t.equal(response.statusCode, 401, 'Durum kodu 401 olmalı');
t.end();
});
t.end();
});
```
Bu testler, Fastify'ın kimlik doğrulama eklentileriyle nasıl etkileşime geçtiğinizi ve korunan rotaları `inject` metoduyla nasıl test edebileceğinizi gösterir. `onRequest` hook'u sayesinde Fastify'ın request lifecycle'ını kullanarak yetkilendirme akışını test etmek oldukça kolaydır.
## Fastify Test Best Practices & Anti-Patterns
Fastify uygulamalarınızı test ederken belirli en iyi uygulamaları takip etmek, test süitinizin verimli, güvenilir ve sürdürülebilir olmasını sağlar. Aynı zamanda kaçınmanız gereken anti-pattern'lar da vardır.
### ✅ Best Practices
* **Testleri İzole Tutun:** Her test, diğer testlerden bağımsız olmalı ve kendi kurulum/yıkım adımlarına sahip olmalıdır. Bu, testlerin sırasının önemli olmamasını ve başarısız bir testin diğerlerini etkilememesini sağlar.
* **Neden Önemli:** Testlerin bağımsızlığı, hata ayıklamayı kolaylaştırır ve test süitinizin kararlılığını artırır. Fastify'da `beforeEach`/`afterEach` veya `tap.test` içinde `app.ready()`/`app.close(