DEV Community

Cover image for nock Nedir? Node.js HTTP İsteklerini Mocklama ve Kodsuz Alternatif
Tobias Hoffmann
Tobias Hoffmann

Posted on • Originally published at apidog.com

nock Nedir? Node.js HTTP İsteklerini Mocklama ve Kodsuz Alternatif

Node.js testleriniz üçüncü taraf bir API kapalı, yavaş veya rate limit altında olduğu için başarısız oluyorsa sorun büyük olasılıkla kodunuz değil, dış bağımlılıktır. Birim testlerini deterministik hale getirmek için HTTP katmanını taklit edin. Node.js tarafında bunun için en yaygın araçlardan biri nock paketidir. Bu yazıda nock’u nasıl kuracağınızı, gerçek bir testte nasıl kullanacağınızı ve ne zaman paylaşılan bir sahte sunucuya geçmeniz gerektiğini göreceksiniz. Tam API referansı için nock GitHub deposu en doğru kaynaktır.

Apidog'u bugün deneyin

nock Nedir?

nock, Node.js testlerinde giden HTTP/HTTPS isteklerini yakalayan bir mock ve expectation kütüphanesidir. Node’un http ve https modüllerini çalışma zamanında intercept eder. Böylece kodunuz fetch, axios, got, node-fetch veya doğrudan http/https ile istek atsa bile gerçek ağ çağrısı yapılmadan önceden tanımladığınız yanıt döndürülür.

Kullanım amacı basittir:

  • Gerçek API’ye istek atmadan test çalıştırmak
  • Testleri hızlı ve deterministik yapmak
  • 500, timeout, rate limit gibi edge case’leri kolayca simüle etmek
  • Bir endpoint’e gerçekten istek atılıp atılmadığını doğrulamak

nock yalnızca Node.js ortamında çalışır. Tarayıcıda çalışmaz ve üretim kodunda kullanılmamalıdır. Bu nedenle projeye devDependency olarak eklenir.

npm install --save-dev nock
Enter fullscreen mode Exit fullscreen mode

veya:

yarn add -D nock
Enter fullscreen mode Exit fullscreen mode

Küçük Bir nock Örneği

Bir API’den kullanıcı bilgisi alan basit bir servisiniz olduğunu varsayalım:

// user-service.js
export async function getUser(id) {
  const res = await fetch(`https://api.example.com/users/${id}`);

  if (!res.ok) {
    throw new Error(`Request failed: ${res.status}`);
  }

  return res.json();
}
Enter fullscreen mode Exit fullscreen mode

Bu fonksiyonu gerçek https://api.example.com adresine gitmeden test etmek için nock kullanabilirsiniz:

// user-service.test.js
import nock from 'nock';
import { getUser } from './user-service.js';

test('API başarılı yanıt verdiğinde kullanıcıyı döndürür', async () => {
  const scope = nock('https://api.example.com')
    .get('/users/42')
    .reply(200, { id: 42, name: 'Ada Lovelace' });

  const user = await getUser(42);

  expect(user).toEqual({ id: 42, name: 'Ada Lovelace' });
  scope.done();
});
Enter fullscreen mode Exit fullscreen mode

Burada olanlar:

  1. nock('https://api.example.com') hedef host’u tanımlar.
  2. .get('/users/42') beklenen HTTP metodunu ve path’i eşleştirir.
  3. .reply(200, {...}) dönecek status code ve body’yi belirler.
  4. getUser(42) çağrıldığında gerçek ağ isteği yapılmaz.
  5. scope.done() beklenen isteğin gerçekten tetiklendiğini doğrular.

scope.done() kullanmak iyi bir alışkanlıktır. Eğer kodunuz beklenen isteği hiç yapmazsa test sessizce geçmez, açıkça fail olur.

Hata Senaryosu Test Etme

Mock kullanmanın en önemli avantajlarından biri, gerçek API’de isteğe bağlı olarak üretmesi zor olan hata durumlarını kolayca simüle etmektir.

Örneğin API 500 dönerse servisinizin hata fırlattığını test edebilirsiniz:

test('API 500 döndürdüğünde hata fırlatır', async () => {
  const scope = nock('https://api.example.com')
    .get('/users/99')
    .reply(500);

  await expect(getUser(99)).rejects.toThrow('Request failed: 500');

  scope.done();
});
Enter fullscreen mode Exit fullscreen mode

Gerçek bir API’nin test anında 500 döndürmesini kontrol edemezsiniz. Ancak nock ile bunu tek satırda tanımlarsınız. Hata simülasyonunu daha detaylı ele almak isterseniz 500 dahili sunucu hatası yanıtını nasıl taklit edeceğinize dair bu rehbere bakabilirsiniz.

Query Parametrelerini Test Etme

Gerçek servislerde çoğu istek query parametreleriyle gelir. Örneğin:

// search-service.js
export async function searchUsers(query) {
  const res = await fetch(`https://api.example.com/users?search=${query}`);

  if (!res.ok) {
    throw new Error(`Request failed: ${res.status}`);
  }

  return res.json();
}
Enter fullscreen mode Exit fullscreen mode

Bunu nock ile şu şekilde test edebilirsiniz:

import nock from 'nock';
import { searchUsers } from './search-service.js';

test('query parametresiyle kullanıcı arar', async () => {
  const scope = nock('https://api.example.com')
    .get('/users')
    .query({ search: 'ada' })
    .reply(200, [
      { id: 42, name: 'Ada Lovelace' }
    ]);

  const users = await searchUsers('ada');

  expect(users).toHaveLength(1);
  expect(users[0].name).toBe('Ada Lovelace');

  scope.done();
});
Enter fullscreen mode Exit fullscreen mode

Query parametrelerinin dinamik olduğu durumlarda daha esnek matcher kullanabilirsiniz:

nock('https://api.example.com')
  .get('/users')
  .query((query) => Boolean(query.search))
  .reply(200, []);
Enter fullscreen mode Exit fullscreen mode

POST Body Eşleştirme

Bir endpoint’e JSON body gönderiyorsanız nock bunu da doğrulayabilir.

Örnek servis:

// create-user.js
export async function createUser(payload) {
  const res = await fetch('https://api.example.com/users', {
    method: 'POST',
    headers: {
      'content-type': 'application/json'
    },
    body: JSON.stringify(payload)
  });

  if (!res.ok) {
    throw new Error(`Request failed: ${res.status}`);
  }

  return res.json();
}
Enter fullscreen mode Exit fullscreen mode

Test:

import nock from 'nock';
import { createUser } from './create-user.js';

test('yeni kullanıcı oluşturur', async () => {
  const scope = nock('https://api.example.com')
    .post('/users', {
      name: 'Ada Lovelace',
      role: 'admin'
    })
    .reply(201, {
      id: 42,
      name: 'Ada Lovelace',
      role: 'admin'
    });

  const user = await createUser({
    name: 'Ada Lovelace',
    role: 'admin'
  });

  expect(user.id).toBe(42);
  expect(user.role).toBe('admin');

  scope.done();
});
Enter fullscreen mode Exit fullscreen mode

Bu test yalnızca yanıtı değil, kodunuzun doğru body ile istek gönderdiğini de doğrular.

Testler Arasında Temizlik Yapın

nock interceptor’ları testler arasında sızarsa hatalı pozitif veya hatalı negatif sonuçlar alabilirsiniz. Bu yüzden her testten sonra temizlik yapın:

import nock from 'nock';

afterEach(() => {
  nock.cleanAll();
});
Enter fullscreen mode Exit fullscreen mode

Ayrıca test sürecinde gerçek ağ bağlantılarını tamamen kapatmak istiyorsanız:

beforeAll(() => {
  nock.disableNetConnect();
});

afterAll(() => {
  nock.enableNetConnect();
});
Enter fullscreen mode Exit fullscreen mode

Bu ayar, testlerde yanlışlıkla gerçek API’ye istek atılmasını engeller. Eğer local server’a izin vermeniz gerekiyorsa:

nock.enableNetConnect('127.0.0.1');
Enter fullscreen mode Exit fullscreen mode

Bilmeniz Gereken Yararlı nock Özellikleri

Temel kullanımın dışında sık kullanılan birkaç özellik vardır.

.persist()

Varsayılan olarak nock interceptor bir kez eşleşince tüketilir. Aynı endpoint test içinde birden fazla kez çağrılacaksa .persist() kullanabilirsiniz:

nock('https://api.example.com')
  .persist()
  .get('/health')
  .reply(200, { status: 'ok' });
Enter fullscreen mode Exit fullscreen mode

.times(n)

Belirli sayıda çağrı bekliyorsanız .times(n) daha kontrollü bir çözümdür:

const scope = nock('https://api.example.com')
  .get('/users/42')
  .times(2)
  .reply(200, { id: 42 });

await getUser(42);
await getUser(42);

scope.done();
Enter fullscreen mode Exit fullscreen mode

.delay(ms)

Timeout veya yavaş API davranışını test etmek için kullanılır:

nock('https://api.example.com')
  .get('/slow-endpoint')
  .delay(2000)
  .reply(200, { ok: true });
Enter fullscreen mode Exit fullscreen mode

RegExp ile path eşleştirme

Dinamik path’ler için RegExp kullanabilirsiniz:

nock('https://api.example.com')
  .get(/\/users\/\d+/)
  .reply(200, { ok: true });
Enter fullscreen mode Exit fullscreen mode

nock.isDone()

Tüm beklenen interceptor’ların kullanılıp kullanılmadığını kontrol eder:

expect(nock.isDone()).toBe(true);
Enter fullscreen mode Exit fullscreen mode

Ancak pratikte belirli bir scope üzerinde scope.done() kullanmak çoğu testte daha okunabilir olur.

nock'un Doğru Araç Olmaktan Çıktığı Noktalar

nock tek bir iş için çok uygundur: otomatik testler sırasında aynı Node.js süreci içindeki HTTP isteklerini yakalamak.

Ancak şu ihtiyaçlarda yetersiz kalır:

  • Frontend ekibi tarayıcıdan mock API’ye erişmek istiyor.
  • Mobil geliştirici simulator’dan aynı fake endpoint’i çağırmak istiyor.
  • QA ekibi manuel test için gerçek bir URL istiyor.
  • Postman, Insomnia veya başka bir API client ile mock endpoint test edilmek isteniyor.
  • Farklı repolardaki ekipler aynı mock response’lar üzerinde anlaşmak istiyor.
  • Backend hazır olmadan demo yapılması gerekiyor.

nock test dosyanızın içinde yaşar. Gerçek bir port açmaz ve dış istemciler tarafından çağrılamaz. Bu durum birim testleri için idealdir; ekipler arası API geliştirme için değildir.

Bu senaryolarda, herkesin erişebileceği gerçek bir URL üzerinde çalışan bir mock server gerekir. Konuyu daha geniş değerlendirmek için taklit sunucuya karşı gerçek sunucu ve API taklidi yazılarına bakabilirsiniz.

nock vs Barındırılan Bir Taklit Sunucu: Apidog

nock ve Apidog aynı problemi farklı katmanlarda çözer.

  • nock: Node.js birim testlerinde süreç içi HTTP intercept eder.
  • Apidog: API şemanızdan paylaşılabilir bir mock server üretir.

Birçok ekip ikisini birlikte kullanır: unit testlerde nock, frontend/QA/entegrasyon akışlarında Apidog mock server.

Apidog, API tasarımınızdan doğrudan mock server oluşturur. Endpoint ve response şemasını tanımlarsınız; Apidog bu tanıma göre canlı bir URL üzerinden gerçekçi yanıtlar döndürür. Böylece test dosyası yazmadan, dil veya framework bağımlılığı olmadan aynı mock endpoint’i ekip içinde paylaşabilirsiniz.

nock Apidog taklit sunucusu
Nerede çalışır Node test sürecinizde Gerçek URL’ye sahip barındırılan sunucu
En iyi kullanım Birim testleri, hata simülasyonu Entegrasyon, manuel test, ekipler arası çalışma
Kimler erişebilir Aynı süreçteki kod URL’ye sahip herhangi bir istemci
Kurulum Her test dosyasında kod API şemanızdan oluşturulur
Dil desteği Yalnızca Node.js Herhangi bir istemci, herhangi bir dil
Gerçekçi veri Her yanıtı siz yazarsınız Şema ve alan adlarından mock veri üretir
Paylaşım Paylaşılamaz Tüm ekiple paylaşılır

Kapsamı netleştirelim: Apidog, Jest veya Mocha birim testlerinizde nock’un yerine geçmez. Tek bir testte fetch çağrısını yakalayıp sonucu doğrulamak istiyorsanız nock doğru araçtır.

Apidog ise mock’un test dosyasından çıkıp başka geliştiriciler, QA veya harici araçlar tarafından çağrılması gerektiğinde kullanılır. Sunucu tarafı örnekler için API testleri için taklit etme kılavuzuna bakabilirsiniz. Ayrıca Apidog’u indirebilir ve mevcut OpenAPI dosyanızdan kısa sürede mock server oluşturabilirsiniz.

nock'a Diğer Alternatifler

nock tek seçenek değildir. Doğru araç, kodunuzun nerede çalıştığına ve mock’un kimler tarafından kullanılacağına bağlıdır.

MSW

MSW (Mock Service Worker), tarayıcıda service worker, Node tarafında interceptor kullanarak istekleri yakalar. Aynı mock tanımlarını frontend ve test ortamlarında kullanmak isteyen ekipler için güçlü bir seçenektir.

Detaylar için resmi MSW belgelerine bakabilirsiniz.

Jest manuel mock’ları

Küçük ve izole testlerde axios gibi bir modülü doğrudan mock’lamak daha basit olabilir:

jest.mock('axios');
Enter fullscreen mode Exit fullscreen mode

Bu yaklaşım hızlıdır ancak sizi belirli bir HTTP client’a bağlar. HTTP seviyesindeki davranışı değil, modül çağrısını test etmiş olursunuz. Bu desen için Jest taklit etme eğitimi incelenebilir.

Test double ve stub kullanımı

Sinon veya Node’un test araçlarıyla fonksiyon seviyesinde stub yazabilirsiniz. Örneğin API çağrısı yapan fonksiyonu tamamen değiştirebilirsiniz. Bu yaklaşım basittir ancak nock’un sağladığı URL, method, header ve body seviyesindeki doğrulamayı kaybedersiniz.

Karar sorusu şudur:

Aynı Node.js süreci içinde birim test mi yazıyorsunuz, yoksa ağ üzerinden erişilebilen sahte bir API’ye mi ihtiyacınız var?

İlki için nock veya MSW uygundur. İkincisi için barındırılan mock server daha doğru çözümdür.

Sıkça Sorulan Sorular

nock ücretsiz mi?

Evet. nock, MIT lisansı altında açık kaynaklıdır ve npm’den ücretsiz olarak yüklenebilir. Projenize geliştirme bağımlılığı olarak ekleyip test paketinizde kullanabilirsiniz.

nock, fetch ve axios ile çalışır mı?

Evet. nock, Node’un http/https katmanında intercept yaptığı için yerel fetch, axios, got, node-fetch ve bu modüllerin üzerine kurulu istemcilerle çalışır.

nock'u tarayıcıda kullanabilir miyim?

Hayır. nock yalnızca Node.js içindir çünkü tarayıcıda bulunmayan Node HTTP modüllerini patch eder. Tarayıcı tarafında MSW kullanabilir veya frontend’i barındırılan bir mock server’a yönlendirebilirsiniz. Daha geniş seçenekler için JavaScript'teki taklit API'leri yazısına bakabilirsiniz.

nock ile mock server arasındaki fark nedir?

nock, test sürecinizin içindeki HTTP isteklerini yakalar ve gerçek bir URL sunmaz. Mock server ise gerçek bir URL üzerinde çalışır ve herhangi bir istemci tarafından çağrılabilir.

Kısa kural:

  • Birim testi yazıyorsanız nock kullanın.
  • Frontend, mobil, QA veya başka ekiplerin aynı sahte API’ye erişmesi gerekiyorsa mock server kullanın.

Özet

nock, Node.js birim testlerinde HTTP mock’lamak için pratik ve güvenilir bir araçtır. Giden istekleri süreç içinde yakalar, tanımladığınız yanıtları döndürür ve 500, timeout, rate limit gibi senaryoları kontrollü şekilde test etmenizi sağlar.

Mock’un test dosyanızın dışına çıkması gerekiyorsa, yani frontend, QA veya başka ekiplerin aynı endpoint’e erişmesi gerekiyorsa barındırılan bir mock server daha uygundur. Apidog, API şemanızdan paylaşılabilir bir mock server oluşturur ve canlı bir URL üzerinden gerçekçi yanıtlar sunar. Apidog’u indirin ve OpenAPI spesifikasyonunuzu çalışan bir mock API’ye dönüştürün.

Top comments (0)