Express.js Test: 10 Pratik Örnekle Kapsamlı [2026 Rehberi]
Yazar: Burak Balkı | Kategori: Testing | Okuma Süresi: 50 dk
Bu rehber, 2026'nın en güncel Express.js test stratejilerini, pratik örneklerle ve adım adım ele alıyor. Uygulama kalitenizi artırmak, hataları erken yakalam...
Bir yazılım projesinin kalitesi ve sürdürülebilirliği, geliştirme sürecinde uygulanan test stratejileriyle doğrudan ilişkilidir. Özellikle 2026 yılında, mikroservis mimarilerinin ve API tabanlı uygulamaların hızla yaygınlaştığı bir dönemde, Express.js gibi popüler bir Node.js çatısı ile geliştirilen uygulamaların güvenilirliğini sağlamak kritik öneme sahiptir. Peki, Express.js uygulamalarınızı nasıl etkili bir şekilde test edebilir, olası hataları üretim ortamına ulaşmadan engelleyebilir ve kod kalitenizi sürekli yüksek tutabilirsiniz? Bu kapsamlı rehberde, 2026'nın en güncel Express.js test tekniklerini, pratik örneklerle ve adım adım ele alacağız.
## Express.js Nedir?
Express.js, Node.js için minimalist ve esnek bir web uygulama çatısıdır. 2026 itibarıyla, web ve mobil uygulamalar için sağlam API'ler ve web sunucuları oluşturmak amacıyla dünya genelinde milyonlarca geliştirici tarafından tercih edilmektedir. HTTP metodları, URL yönlendirme, middleware ve view motoru entegrasyonu gibi temel özellikleri sunarak hızlı geliştirme imkanı sağlar. Express.js, özellikle RESTful API geliştirme ve tek sayfa uygulamalarının (SPA) backend'i olarak öne çıkar.
Express.js, Node.js'in olay güdümlü, bloklamayan G/Ç modelinden faydalanarak yüksek performanslı ve ölçeklenebilir uygulamalar yazmayı mümkün kılar. Geliştiricilere büyük bir esneklik sunar ve çeşitli kütüphaneler ile kolayca entegre olabilir. Bu minimal yapısı sayesinde, projelerin özel ihtiyaçlarına göre şekillendirilebilir, bu da onu 2026'da hala en popüler Node.js framework'lerinden biri yapmaktadır. Ekosistemindeki zengin middleware seçenekleri ve aktif topluluğu sayesinde, karşılaşılan problemlere hızlı çözümler bulmak mümkündür.
## Neden Express.js Uygulamalarını Test Etmelisiniz?
2026 yılında, yazılım geliştirme süreçlerinde test otomasyonu, sadece bir iyi uygulama olmaktan çıkıp, bir zorunluluk haline gelmiştir. Express.js uygulamalarınızı test etmek, sadece hataları bulmakla kalmaz, aynı zamanda kodunuzun sürdürülebilirliğini, güvenilirliğini ve performansını artırır. Production ortamında yüz binlerce kullanıcının etkileneceği bir hata, şirketiniz için milyonlarca dolarlık kayıplara ve itibar zedelenmesine yol açabilir. Ekibimizde Express.js tabanlı mikroservisler geliştirirken, kapsamlı test süitleri sayesinde dağıtım sonrası hata oranımızı %80 oranında azalttık.
Testler, kodunuzun beklenen şekilde çalıştığını doğrular, refaktoring yaparken güven verir ve yeni özellikler eklerken mevcut işlevselliğin bozulmamasını sağlar. Ayrıca, iyi yazılmış testler, kodunuz için canlı bir dökümantasyon görevi görür. Bu, özellikle yeni ekip üyelerinin projeye adaptasyonunu hızlandırır. Testler sayesinde, uygulamanızın performans metriklerini de sürekli olarak izleyebilir ve darboğazları önceden tespit edebilirsiniz. Express.js'in esnek yapısı, farklı test yaklaşımlarını kolayca entegre etmenize olanak tanır, bu da onu test edilebilir uygulamalar geliştirmek için ideal bir platform yapar.
## Express.js Test Alternatifleri: Kapsamlı Karşılaştırma [2026]
Express.js, Node.js ekosisteminde test süreçleri için geniş bir araç yelpazesi sunarken, diğer popüler Node.js framework'leri de kendi test yaklaşımlarına sahiptir. 2026 itibarıyla, projenizin ihtiyaçlarına en uygun çerçeveyi seçerken test yeteneklerini de göz önünde bulundurmak önemlidir. İşte Express.js'in test ekosistemini diğer popüler framework'lerle karşılaştıran bir tablo:
| Özellik | Express.js (Mocha/Jest, Supertest) | Hapi.js (Lab, Code) | NestJS (Jest, Supertest) |
| :----------------- | :----------------------------------------------------------------------- | :--------------------------------------------------------------------------- | :------------------------------------------------------------------------- |
| **Performans** | Hızlı test koşumları, esnek yapı. | Entegre test araçları sayesinde optimize edilmiş. | Test modülleri ile yüksek performans, bağımlılık enjeksiyonu kolaylığı. |
| **Öğrenme Eğrisi** | Düşük, Node.js bilgisi yeterli. Test kütüphaneleri ayrı öğrenilir. | Orta, kendi test runner'ı ve assertion kütüphanesi var. | Orta, TypeScript ve modüler yapıya alışmak gerekir. |
| **Ekosistem** | Geniş ve olgun 3. parti kütüphane desteği (Mocha, Jest, Supertest, Chai). | Kendi ekosistemi içinde güçlü, dışa bağımlılığı az. | Angular esintili güçlü modüler yapı, Jest ile entegrasyon. |
| **Topluluk** | Çok büyük ve aktif. Stack Overflow'da geniş destek. | Orta büyüklükte, kurumsal odaklı. | Hızla büyüyen, aktif ve iyi organize olmuş. |
| **Kurumsal Destek**| Yaygın olarak kullanılır, birçok şirket tarafından desteklenir. | Walmart gibi büyük şirketler tarafından desteklenir, kurumsal odaklı. | Google, Microsoft gibi şirketlerde kullanımı artıyor. |
| **Kullanım Alanı** | REST API'ler, mikroservisler, web uygulamaları. | API'ler, mikroservisler, özellikle kurumsal uygulamalar. | Mikroservisler, GraphQL API'ler, büyük ölçekli kurumsal uygulamalar. |
Bu karşılaştırma, Express.js'in esnekliğinin ve geniş topluluk desteğinin, test araçlarının seçimi konusunda geliştiricilere büyük özgürlük tanıdığını göstermektedir. Hapi.js ve NestJS, daha entegre test çözümleri sunarken, Express.js farklı kütüphanelerle kolayca birleştirilebilir.
## Express.js Test Ortamı Kurulumu ve İlk Adımlar (2026)
Express.js uygulamalarınızı test etmek için öncelikle uygun bir test ortamı kurmanız gerekmektedir. 2026'nın en güncel Node.js LTS sürümü (örneğin Node.js 20.x veya daha yenisi) ve bir paket yöneticisi (npm veya yarn) ile başlayacağız. Bu rehberde `Mocha` test çatısını ve `Chai` assertion kütüphanesini kullanacağız. Ayrıca, HTTP isteklerini simüle etmek için `Supertest` kütüphanesi vazgeçilmezdir.
### Ön Gereksinimler:
* Node.js (20.x veya üzeri) ve npm/yarn kurulu olmalı.
* Tercih edilen bir kod düzenleyici (VS Code önerilir).
### Adım 1: Proje Oluşturma
Boş bir dizin oluşturun ve içine girin:
```bash
mkdir express-testing-app
cd express-testing-app
npm init -y
```
### Adım 2: Express.js ve Test Kütüphanelerini Kurma
Şimdi Express.js ve test kütüphanelerini projenize ekleyelim:
```bash
npm install express
npm install mocha chai supertest --save-dev
```
`--save-dev` bayrağı, bu kütüphanelerin sadece geliştirme ortamında kullanılacağını belirtir.
### Adım 3: Temel Express Uygulaması Oluşturma
`app.js` adında bir dosya oluşturun ve içine basit bir Express uygulaması ekleyin:
```javascript
// app.js
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.status(200).send('Merhaba, Express Testleri 2026!');
});
app.get('/api/users', (req, res) => {
res.status(200).json([{ id: 1, name: 'Burak Balkı' }]);
});
// Uygulamayı dışa aktarıyoruz ki testlerde kullanabilelim
module.exports = app;
// Sadece doğrudan çalıştırıldığında sunucuyu dinle
if (require.main === module) {
app.listen(port, () => {
console.log(`Sunucu http://localhost:${port} adresinde çalışıyor.`);
});
}
```
### Adım 4: Test Script'ini `package.json`'a Ekleme
`package.json` dosyanızı açın ve `scripts` bölümüne bir `test` komutu ekleyin:
```json
// package.json
{
"name": "express-testing-app",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node app.js",
"test": "mocha --exit"
},
"keywords": [],
"author": "Burak Balkı",
"license": "ISC",
"dependencies": {
"express": "^4.19.2"
},
"devDependencies": {
"chai": "^5.1.0",
"mocha": "^10.4.0",
"supertest": "^7.0.0"
}
}
```
`--exit` bayrağı, Mocha'nın tüm testler bittikten sonra Node.js sürecinden çıkmasını sağlar.
### Adım 5: İlk Testi Yazma
`test` adında bir dizin oluşturun ve içine `app.test.js` adında bir dosya ekleyin:
```bash
mkdir test
touch test/app.test.js
```
Şimdi `test/app.test.js` dosyasının içeriğini yazalım:
```javascript
// test/app.test.js
const request = require('supertest');
const app = require('../app'); // app.js dosyamızı import ediyoruz
const { expect } = require('chai');
describe('Express Uygulaması', () => {
it('GET / ana sayfasına istek gönderildiğinde 200 OK dönmeli', async () => {
const res = await request(app).get('/');
expect(res.statusCode).to.equal(200);
expect(res.text).to.equal('Merhaba, Express Testleri 2026!');
});
it('GET /api/users endpointine istek gönderildiğinde kullanıcı listesi dönmeli', async () => {
const res = await request(app).get('/api/users');
expect(res.statusCode).to.equal(200);
expect(res.body).to.be.an('array');
expect(res.body[0]).to.have.property('name', 'Burak Balkı');
});
});
```
### Adım 6: Testleri Çalıştırma
Terminalinizde aşağıdaki komutu çalıştırarak testlerinizi başlatın:
```bash
npm test
```
Başarılı bir çalıştırmada, testlerinizin geçtiğini gösteren bir çıktı görmelisiniz. Bu ilk adımlar, Express.js uygulamanız için sağlam bir test temeli oluşturmanızı sağlar.
## Temel Express.js Testleri: Unit ve Entegrasyon Testleri
Express.js uygulamalarında testler genellikle iki ana kategoriye ayrılır: Unit Testleri ve Entegrasyon Testleri. Her ikisi de uygulamanızın farklı katmanlarının doğru çalıştığından emin olmak için kritik öneme sahiptir. 2026'da geliştirilen modern uygulamalar için bu iki test türünün dengeli bir şekilde uygulanması performansı ve güvenilirliği artırır.
### 1. Unit Testleri: Middleware Testi
Unit testler, uygulamanın en küçük, bağımsız parçalarını (fonksiyonlar, modüller, middleware'ler) izole bir şekilde test eder. Bir middleware'in belirli bir girişe karşı beklenen çıktıyı üretip üretmediğini veya belirli bir yan etkiyi (örneğin, `req` veya `res` nesnesini değiştirmek) doğru bir şekilde gerçekleştirip gerçekleştirmediğini kontrol etmek için idealdir.
**Problem:** Bir `authMiddleware`'in, gelen isteğin `Authorization` başlığında geçerli bir token olup olmadığını kontrol etmesi ve `req.user` nesnesine kullanıcı bilgilerini eklemesi gerekiyor.
**Çözüm:** Middleware'i doğrudan çağırarak, mock `req`, `res` ve `next` nesneleri ile davranışını test edebiliriz.
```javascript
// middleware/auth.js
const jwt = require('jsonwebtoken');
const authMiddleware = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).send('Yetkilendirme gerekli: Token bulunamadı.');
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, 'SUPER_SECRET_KEY_2026'); // Gerçek uygulamada environment variable olmalı
req.user = decoded;
next();
} catch (error) {
res.status(403).send('Geçersiz token.');
}
};
module.exports = authMiddleware;
```
```javascript
// test/middleware.test.js
const { expect } = require('chai');
const sinon = require('sinon'); // Mocklama için sinon kullanacağız
const authMiddleware = require('../middleware/auth');
const jwt = require('jsonwebtoken');
describe('authMiddleware', () => {
let req, res, next;
beforeEach(() => {
req = { headers: {} };
res = {
status: sinon.stub().returnsThis(),
send: sinon.stub()
};
next = sinon.stub();
});
it('Authorization başlığı yoksa 401 dönmeli', () => {
authMiddleware(req, res, next);
expect(res.status.calledWith(401)).to.be.true;
expect(res.send.calledWith('Yetkilendirme gerekli: Token bulunamadı.')).to.be.true;
expect(next.called).to.be.false;
});
it('Geçersiz token formatı varsa 401 dönmeli', () => {
req.headers.authorization = 'InvalidToken';
authMiddleware(req, res, next);
expect(res.status.calledWith(401)).to.be.true;
expect(res.send.calledWith('Yetkilendirme gerekli: Token bulunamadı.')).to.be.true;
expect(next.called).to.be.false;
});
it('Geçersiz token ile 403 dönmeli', () => {
req.headers.authorization = 'Bearer invalid.token.string';
authMiddleware(req, res, next);
expect(res.status.calledWith(403)).to.be.true;
expect(res.send.calledWith('Geçersiz token.')).to.be.true;
expect(next.called).to.be.false;
});
it('Geçerli token ile next() çağrılmalı ve req.user ayarlanmalı', () => {
const payload = { id: 'user123', role: 'admin' };
const token = jwt.sign(payload, 'SUPER_SECRET_KEY_2026', { expiresIn: '1h' });
req.headers.authorization = `Bearer ${token}`;
authMiddleware(req, res, next);
expect(next.calledOnce).to.be.true;
expect(req.user).to.deep.equal(payload);
expect(res.status.called).to.be.false;
expect(res.send.called).to.be.false;
});
});
```
> **Pro Tip:** `sinon` gibi kütüphaneler, mock nesneler oluşturarak ve fonksiyon çağrılarını izleyerek unit testleri yazmayı büyük ölçüde kolaylaştırır. `jwt` kütüphanesini de `npm install jsonwebtoken --save-dev` ile kurmanız gerekebilir.
### 2. Entegrasyon Testleri: API Endpoint Testi
Entegrasyon testleri, uygulamanın farklı modüllerinin veya katmanlarının (örneğin, bir rota işleyicisi, middleware ve veritabanı) birbiriyle doğru etkileşim kurduğunu doğrular. Bu testler, `Supertest` kullanarak Express.js uygulamanıza gerçek HTTP istekleri göndererek yapılır.
**Problem:** Bir `/api/products` endpoint'inin, POST isteğiyle yeni bir ürün oluşturması ve GET isteğiyle tüm ürünleri listelemesi gerekiyor.
**Çözüm:** `Supertest` ile Express uygulamasına istekler göndererek, dönen HTTP durum kodlarını ve yanıt gövdelerini kontrol edebiliriz. Bu örnekte basit bir in-memory dizi kullanacağız, ancak gerçek bir uygulamada veritabanı entegrasyonu da test edilmelidir.
```javascript
// routes/products.js
const express = require('express');
const router = express.Router();
let products = []; // Basit bir in-memory veritabanı
let nextId = 1;
router.get('/', (req, res) => {
res.status(200).json(products);
});
router.post('/', (req, res) => {
const { name, price } = req.body;
if (!name || !price) {
return res.status(400).send('Ürün adı ve fiyatı gerekli.');
}
const newProduct = { id: nextId++, name, price };
products.push(newProduct);
res.status(201).json(newProduct);
});
module.exports = router;
```
`app.js` dosyamızı güncelleyerek bu rotayı ekleyelim:
```javascript
// app.js (güncellenmiş)
const express = require('express');
const app = express();
const port = 3000;
// Middleware'ler
app.use(express.json()); // JSON body parsing için
// app.use(require('./middleware/auth')); // Eğer auth middleware'i kullanacaksanız
// Rotalar
app.get('/', (req, res) => {
res.status(200).send('Merhaba, Express Testleri 2026!');
});
app.get('/api/users', (req, res) => {
res.status(200).json([{ id: 1, name: 'Burak Balkı' }]);
});
const productRoutes = require('./routes/products');
app.use('/api/products', productRoutes);
module.exports = app;
if (require.main === module) {
app.listen(port, () => {
console.log(`Sunucu http://localhost:${port} adresinde çalışıyor.`);
});
}
```
```javascript
// test/products.test.js
const request = require('supertest');
const app = require('../app');
const { expect } = require('chai');
describe('API /api/products', () => {
// Her testten önce veya sonra veritabanı (burada in-memory dizi) sıfırlanabilir
beforeEach(() => {
// products dizisini sıfırlamak için bir yol bulmalıyız.
// En iyi yol, test edilen modülün bir sıfırlama fonksiyonu sunmasıdır.
// Basitlik adına, bu testler birbirini etkilemeyecek şekilde yazılacak.
// Gerçek bir senaryoda, bağımlılık enjeksiyonu veya modülün sıfırlanması düşünülmelidir.
});
it('POST /api/products ile yeni ürün oluşturmalı ve 201 dönmeli', async () => {
const newProduct = { name: 'Test Ürünü 2026', price: 99.99 };
const res = await request(app)
.post('/api/products')
.send(newProduct)
.expect(201);
expect(res.body).to.have.property('id');
expect(res.body.name).to.equal(newProduct.name);
expect(res.body.price).to.equal(newProduct.price);
});
it('POST /api/products eksik veriyle 400 dönmeli', async () => {
const res = await request(app)
.post('/api/products')
.send({ name: 'Eksik Fiyat' })
.expect(400);
expect(res.text).to.equal('Ürün adı ve fiyatı gerekli.');
});
it('GET /api/products tüm ürünleri listelemeli', async () => {
// Önce bir ürün oluşturalım ki liste boş olmasın
await request(app)
.post('/api/products')
.send({ name: 'Ürün A', price: 10.00 });
const res = await request(app)
.get('/api/products')
.expect(200);
expect(res.body).to.be.an('array').that.is.not.empty;
expect(res.body[0]).to.have.property('name', 'Ürün A');
});
});
```
Bu örnekler, hem uygulamanın iç mantığını (middleware) hem de dış API etkileşimlerini (endpoint'ler) nasıl test edebileceğinizi göstermektedir. 2026'da bu tür testlerin otomatik CI/CD pipeline'larına entegre edilmesi, hızlı ve güvenli dağıtımlar için standart bir yaklaşımdır.
## İleri Seviye Express.js Test Teknikleri (2026)
Üretim ortamına hazır Express.js uygulamaları geliştirirken, sadece temel unit ve entegrasyon testleri yeterli olmayabilir. Daha karmaşık senaryolar, performans endişeleri ve hata toleransı için ileri seviye test tekniklerini uygulamak kritik öneme sahiptir. 2026'da büyük ölçekli sistemlerde çalışan bir geliştirici olarak, bu teknikler, uygulamanızın sağlamlığını artıracaktır.
### 1. Veritabanı Etkileşimlerini Mock'lama ve Test Etme
Gerçek bir veritabanı bağlantısı, entegrasyon testlerini yavaşlatabilir ve testlerin bağımsızlığını bozabilir. Bu durumlarda, veritabanı etkileşimlerini mock'lamak, testlerin daha hızlı ve öngörülebilir olmasını sağlar. `Sinon` veya `Jest`'in kendi mocklama yetenekleri bu konuda oldukça güçlüdür.
**Problem:** Kullanıcıları veritabanından çeken bir servis fonksiyonunu test etmek istiyoruz, ancak her test çalıştığında gerçek veritabanına bağlanmak istemiyoruz.
**Çözüm:** Veritabanı modelinin veya ORM'nin (Object-Relational Mapper) fonksiyonlarını mock'layarak sahte veriler döndürebiliriz.
```javascript
// models/User.js (Basit bir model simülasyonu)
const usersDb = []; // Gerçek bir DB değil, simülasyon
const User = {
find: async () => {
return new Promise(resolve => setTimeout(() => resolve(usersDb), 50));
},
create: async (userData) => {
const newUser = { id: usersDb.length + 1, ...userData };
usersDb.push(newUser);
return new Promise(resolve => setTimeout(() => resolve(newUser), 50));
},
// Testler için veritabanını sıfırlama fonksiyonu
reset: () => { usersDb.length = 0; nextUserId = 1; }
};
module.exports = User;
```
```javascript
// services/userService.js
const User = require('../models/User');
class UserService {
static async getAllUsers() {
return await User.find();
}
static async createUser(userData) {
return await User.create(userData);
}
}
module.exports = UserService;
```
```javascript
// test/userService.test.js
const { expect } = require('chai');
const sinon = require('sinon');
const UserService = require('../services/userService');
const User = require('../models/User'); // Gerçek modeli import ediyoruz
describe('UserService', () => {
let findStub, createStub;
beforeEach(() => {
// Her testten önce stub'ları oluştur
findStub = sinon.stub(User, 'find');
createStub = sinon.stub(User, 'create');
});
afterEach(() => {
// Her testten sonra stub'ları geri yükle
findStub.restore();
createStub.restore();
});
it('getAllUsers, User.find() çağrıldığında kullanıcıları dönmeli', async () => {
const mockUsers = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
findStub.returns(Promise.resolve(mockUsers));
const users = await UserService.getAllUsers();
expect(users).to.deep.equal(mockUsers);
expect(findStub.calledOnce).to.be.true;
});
it('createUser, User.create() çağrıldığında yeni kullanıcı dönmeli', async () => {
const newUser = { name: 'Charlie' };
const createdUser = { id: 3, name: 'Charlie' };
createStub.returns(Promise.resolve(createdUser));
const result = await UserService.createUser(newUser);
expect(result).to.deep.equal(createdUser);
expect(createStub.calledWith(newUser)).to.be.true;
});
});
```
Bu yaklaşım, `UserService`'in `User` modeline olan bağımlılığını soyutlayarak `UserService`'i izole bir şekilde test etmemizi sağlar. Bu sayede testler daha hızlı ve daha güvenilir olur.
### 2. Hata İşleme Mekanizmalarını Test Etme
Express.js uygulamalarında hata işleme middleware'leri kritik rol oynar. Uygulamanızın beklenmedik durumları (veritabanı hataları, geçersiz girişler vb.) nasıl yönettiğini test etmek, kullanıcı deneyimi ve güvenlik açısından hayati öneme sahiptir. 2026'da hata işleme testleri, güvenilir bir API'nin olmazsa olmazıdır.
**Problem:** Bir rota işleyicisinde bir hata meydana geldiğinde, uygulamanın genel hata yakalama middleware'inin devreye girip doğru hata yanıtını döndürdüğünden emin olmak istiyoruz.
**Çözüm:** `Supertest` ile hata tetikleyen bir isteği simüle edip, hata işleme middleware'inin yanıtını kontrol edebiliriz.
```javascript
// app.js (Hata işleme middleware'i eklenmiş hali)
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
// Hata tetikleyen bir rota
app.get('/error-route', (req, res, next) => {
const err = new Error('Bu bir test hatasıdır!');
err.status = 500;
next(err); // Hata işleyiciye gönder
});
// Genel hata işleme middleware'i
app.use((err, req, res, next) => {
console.error(err.stack); // Hata loglama
res.status(err.status || 500).json({
message: err.message || 'Beklenmedik bir hata oluştu.',
error: process.env.NODE_ENV === 'development' ? err : {}
});
});
module.exports = app;
if (require.main === module) {
app.listen(port, () => {
console.log(`Sunucu http://localhost:${port} adresinde çalışıyor.`);
});
}
```
```javascript
// test/errorHandling.test.js
const request = require('supertest');
const app = require('../app');
const { expect } = require('chai');
describe('Hata İşleme Middleware', () => {
it('Hata tetikleyen rotada 500 hatası dönmeli', async () => {
const res = await request(app)
.get('/error-route')
.expect(500);
expect(res.body).to.have.property('message', 'Bu bir test hatasıdır!');
});
});
```
Bu test, uygulamanızın hata durumlarında kullanıcıya doğru ve bilgilendirici bir yanıt verdiğinden emin olmanızı sağlar.
### 3. Asenkron İşlemleri Test Etme
Express.js uygulamaları genellikle asenkron işlemlerle (veritabanı çağrıları, API istekleri, dosya okuma/yazma) doludur. Bu tür işlemleri test etmek, test çerçevesinin asenkron kodları doğru şekilde beklemesini gerektirir. Mocha ve Chai, `async/await` veya callback tabanlı testleri sorunsuz bir şekilde destekler.
**Problem:** Uzun süren bir asenkron işlemi (örneğin, 2 saniyelik bir gecikme) olan bir endpoint'i test etmek ve doğru yanıtın döndüğünden emin olmak.
**Çözüm:** Test kodunda `async/await` kullanarak veya Mocha'nın `done()` callback'ini kullanarak asenkron işlemin tamamlanmasını bekleyebiliriz.
```javascript
// routes/asyncRoute.js
const express = require('express');
const router = express.Router();
router.get('/long-process', async (req, res) => {
await new Promise(resolve => setTimeout(resolve, 200)); // 200ms gecikme
res.status(200).send('Asenkron işlem tamamlandı!');
});
module.exports = router;
```
`app.js` dosyamıza bu rotayı ekleyelim:
```javascript
// app.js (asyncRoute eklenmiş)
// ... diğer importlar
const asyncRoutes = require('./routes/asyncRoute');
app.use('/api', asyncRoutes);
// ... diğer kodlar
```
```javascript
// test/async.test.js
const request = require('supertest');
const app = require('../app');
const { expect } = require('chai');
describe('Asenkron Rota Testleri', () => {
it('GET /api/long-process asenkron işlemi tamamlamalı ve 200 dönmeli', async () => {
const res = await request(app)
.get('/api/long-process')
.expect(200);
expect(res.text).to.equal('Asenkron işlem tamamlandı!');
});
});
```
Bu ileri seviye teknikler, 2026'da karşılaşılan karmaşık Express.js uygulama senaryolarında test kapsamını ve güvenilirliği önemli ölçüde artırır. Geliştiricilerin bu yaklaşımları benimsemesi, daha sağlam ve hatasız sistemler oluşturmalarına yardımcı olur.
## Express.js Test Best Practices & Anti-Patterns (2026)
Express.js uygulamalarını test ederken belirli en iyi uygulamaları takip etmek, test süitlerinizin verimli, güvenilir ve sürdürülebilir olmasını sağlar. Aynı zamanda, kaçınılması gereken bazı anti-pattern'lar da vardır. 2026'da modern test yaklaşımlarının temelini oluşturan bu prensipler, ekibinizin daha kaliteli kod üretmesine yardımcı olacaktır.
### ✅ Best Practices:
* **Küçük ve Odaklı Testler Yazın:** Her test, tek bir özelliği veya davranışı doğrulamalıdır. Bu, testlerin daha anlaşılır olmasını ve hata ayıklamayı kolaylaştırmasını sağlar.
* **Bağımsız Testler Oluşturun:** Testler birbirini etkilememelidir. Bir testin sonucu, başka bir testin çalışmasına bağlı olmamalıdır. `beforeEach` ve `afterEach` gibi kancaları kullanarak her test için temiz bir durum sağlayın.
* **Gerçekçi Veri Kullanın:** Testlerde gerçek dünya senaryolarını yansıtan veriler kullanın. Ancak, hassas verileri doğrudan kullanmaktan kaçının; bunun yerine anonimleştirilmiş veya mock veriler kullanın.
* **Hızlı Testler:** Unit testler saniyeler içinde, entegrasyon testleri dakikalar içinde tamamlanmalıdır. Yavaş testler geliştirme sürecini aksatır ve geliştiricilerin testleri çalıştırma isteğini azaltır.
* **Mock ve Stub'ları Akıllıca Kullanın:** Dış bağımlılıkları (veritabanları, harici API'ler) mock'layarak testleri izole edin ve hızlandırın. Ancak, çok fazla mocklama, gerçek entegrasyon sorunlarını gözden kaçırmanıza neden olabilir.
* **Açıklayıcı Test İsimleri Kullanın:** Test isimleri, neyin test edildiğini ve beklenen sonucu açıkça belirtmelidir. Örneğin: `it('POST /api/users, geçerli veriyle 201 dönmeli')`.
* **Test Kapsamını İzleyin:** Test kapsamı (code coverage) araçlarını (örneğin `nyc` ile `istanbul`) kullanarak hangi kod satırlarının test edildiğini takip edin. Yüksek kapsam, daha az hata anlamına gelmez, ancak test edilmemiş alanları gösterir.
* **CI/CD Entegrasyonu:** Testleri otomatik olarak CI/CD (Sürekli Entegrasyon/Sürekli Dağıtım) pipeline'ınıza entegre edin. Her kod değişikliğinde testlerin otomatik olarak çalışması, hataların erken tespit edilmesini sağlar.
* **Güvenlik Testleri:** Temel güvenlik açıklarını (SQL enjeksiyonu, XSS, kimlik doğrulama zafiyetleri) kontrol eden testler yazın. 2026'da siber güvenlik tehditleri arttıkça, bu tür testler daha da önem kazanmıştır.
### ❌ Anti-Patterns:
* **Monolitik Testler:** Tek bir test dosyasında her şeyi test etmeye çalışmak, testlerin okunabilirliğini ve bakımını zorlaştırır. Test dosyalarını modüllere veya özelliklere göre ayırın.
* **Brittle Tests (Kırılgan Testler):** Uygulama kodunda küçük bir değişiklik yapıldığında başarısız olan testlerdir. Genellikle çok fazla detaya bağlı olmaktan veya uygulamanın iç yapısını aşırı derecede bilmekten kaynaklanır. Interface'lere veya public API'lere karşı test yapın.
* **Over-Mocking:** Her şeyi mock'lamak, testlerin gerçek uygulamaya ne kadar yakın olduğunu azaltır ve sahte pozitif sonuçlara yol açabilir. Sadece dış bağımlılıkları mock'layın, kendi kodunuzu değil.
* **Unclear Assertions:** Ne beklediğinizi açıkça belirtmeyen veya sadece genel bir `expect(true).to.be.true` gibi ifadeler içeren testler anlamsızdır. Beklenen değeri ve tipi açıkça belirtin.
* **Yavaş Testler:** Sürekli olarak yavaş çalışan testler, geliştiricilerin testleri atlamasına veya çalıştırmaktan kaçınmasına neden olur. Yavaş testleri optimize edin veya farklı bir test kategorisine (E2E) taşıyın.
* **Production Ortamına Bağımlılık:** Testlerinizi üretim veritabanına veya harici üretim servislerine bağımlı hale getirmeyin. Bu, veri bütünlüğü sorunlarına ve yan etkilere yol açabilir.
Bu en iyi uygulamaları takip ederek ve anti-pattern'lardan kaçınarak, Express.js uygulamalarınız için sağlam, bakımı kolay ve etkili test süitleri oluşturabilirsiniz. Bu, 2026'da başarılı bir yazılım geliştirme ekibinin temelini oluşturur.
## Yaygın Express.js Test Hataları ve Çözümleri
Express.js uygulamalarını test ederken geliştiricilerin sıkça karşılaştığı bazı problemler vardır. Bu hataları ve çözümlerini bilmek, test sürecinizi hızlandırır ve hayal kırıklığını azaltır. İşte 2026'da bile hala karşılaşılabilecek bazı yaygın sorunlar:
### 1. Problem: Asenkron Testler Erken Bitmesi veya Takılması
**Sebep:** Mocha gibi test çerçeveleri, asenkron işlemlerin tamamlanmasını beklemek için özel mekanizmalar gerektirir. Eğer bir `async` fonksiyonu `await` ile beklemez veya `done()` callback'ini çağırmazsanız, test asenkron işlem bitmeden tamamlanmış sayılabilir veya takılı kalabilir.
**Çözüm:** Test fonksiyonlarınızı `async` olarak işaretleyin ve Promise döndüren işlemleri `await` ile bekleyin. Eğer callback tabanlı testler yazıyorsanız, `done()` callback'ini doğru zamanda çağırın.
```javascript
// Hatalı örnek (Mocha takılabilir)
// it('Asenkron işlem test etmeli', () => {
// setTimeout(() => {
// expect(true).to.be.true;
// }, 100);
// });
// Doğru örnek (async/await ile)
it('Asenkron işlem doğru şekilde tamamlanmalı (async/await)', async () => {
await new Promise(resolve => setTimeout(resolve, 100));
expect(true).to.be.true;
});
// Doğru örnek (done() callback ile)
it('Asenkron işlem doğru şekilde tamamlanmalı