GoDasturchi
Testing Middleware in Isolation

Testing Middleware in Isolation

Middleware'ni ALOHIDA sinash

Mashinaning tormoz tizimini sinash uchun BUTUN mashinani YO'LGA chiqarish shart emas — tormoz qismini STENDGA o'rnatib, ALOHIDA bosim berib ko'rish MUMKIN va ANIQROQ. Middleware'ni sinashda ham xuddi shunday: BUTUN ilovani (BookStore, real handler'lar) ISHGA TUSHIRISH shart emas — middleware'ni SODDA, "soxta" (fake/spy) next handler bilan ALOHIDA sinash mumkin, bu esa test nimani TEKSHIRAYOTGANINI ANIQROQ qiladi.

example.go
package main

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

var apiKeys = map[string]string{"key-abc": "Acme Corp"}

func requireAPIKey(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		key := r.Header.Get("X-API-Key")
		if _, ok := apiKeys[key]; !ok {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
		next(w, r)
	}
}

func TestRequireAPIKey(t *testing.T) {
	var calledNext bool
	// SPY handler: HAQIQIY ish qilmaydi, faqat "meni chaqirishdimi?" deb BELGILAYDI
	next := func(w http.ResponseWriter, r *http.Request) {
		calledNext = true
		w.WriteHeader(http.StatusOK)
	}
	handler := requireAPIKey(next)

	tests := []struct {
		name       string
		apiKey     string
		wantStatus int
		wantCalled bool
	}{
		{"kalit yoq", "", http.StatusUnauthorized, false},
		{"togri kalit", "key-abc", http.StatusOK, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			calledNext = false
			req := httptest.NewRequest("GET", "/books", nil)
			if tt.apiKey != "" {
				req.Header.Set("X-API-Key", tt.apiKey)
			}
			rec := httptest.NewRecorder()
			handler(rec, req)
			if rec.Code != tt.wantStatus {
				t.Errorf("status = %d, kutilgan %d", rec.Code, tt.wantStatus)
			}
			if calledNext != tt.wantCalled {
				t.Errorf("calledNext = %v, kutilgan %v", calledNext, tt.wantCalled)
			}
		})
	}
}

next — HAQIQIY BookStore yoki JSON javob YOZMAYDI, u FAQAT calledNext = true deb BELGILAYDI. Bu — MIDDLEWARE'ga xos test naqshi: biz createHandler yoki getHandlerNING to'g'ri ishlashini emas, requireAPIKeyNING O'ZI to'g'ri ishlashini ("ruxsat bo'lmasa next chaqirilmasin", "ruxsat bo'lsa chaqirilsin") sinaymiz. Agar next chaqirilgan bo'lsa-yu, lekin STATUS kutilganidan farq qilsa — bu middleware muammosi EMAS, nextNING o'ZI muammo, deb ANIQ ajratish mumkin.

calledNext — ikkita AJRALIB turadigan narsani BIR VAQTDA tekshiradi: (1) status kod TO'G'RImi, (2) next CHAQIRILDIMI yoki YO'Qmi. Faqat statusni tekshirish YETARLI EMAS: masalan middleware xato bilan HAM 200 qaytarib, HAM nextni chaqirmasligi mumkin — calledNext buni FOSH qiladi.

>_ Exercise

NOTO'G'RI (lekin BO'SH bo'lmagan) kalit holatini ham jadvalga qo'shing.

  • tests jadvaliga {"notogri kalit", "wrong", http.StatusUnauthorized, false} qatorini qo'shing
  • BOSHQA hech narsani o'zgartirmang

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Middleware'ni ALOHIDA sinash — HAQIQIY biznes handler o'rniga, oddiy "spy" (kuzatuvchi) funksiya bilan, middleware'ning FAQAT o'ziga xos xatti-harakatini (chaqirilishi yoki chaqirilmasligi) TEKSHIRISHGA imkon beradi.

NEXT UP

Putting It All Together: Wiring the Full API

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

Testing Middleware in Isolation

Middleware'ni ALOHIDA sinash

Mashinaning tormoz tizimini sinash uchun BUTUN mashinani YO'LGA chiqarish shart emas — tormoz qismini STENDGA o'rnatib, ALOHIDA bosim berib ko'rish MUMKIN va ANIQROQ. Middleware'ni sinashda ham xuddi shunday: BUTUN ilovani (BookStore, real handler'lar) ISHGA TUSHIRISH shart emas — middleware'ni SODDA, "soxta" (fake/spy) next handler bilan ALOHIDA sinash mumkin, bu esa test nimani TEKSHIRAYOTGANINI ANIQROQ qiladi.

example.go
package main

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

var apiKeys = map[string]string{"key-abc": "Acme Corp"}

func requireAPIKey(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		key := r.Header.Get("X-API-Key")
		if _, ok := apiKeys[key]; !ok {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
		next(w, r)
	}
}

func TestRequireAPIKey(t *testing.T) {
	var calledNext bool
	// SPY handler: HAQIQIY ish qilmaydi, faqat "meni chaqirishdimi?" deb BELGILAYDI
	next := func(w http.ResponseWriter, r *http.Request) {
		calledNext = true
		w.WriteHeader(http.StatusOK)
	}
	handler := requireAPIKey(next)

	tests := []struct {
		name       string
		apiKey     string
		wantStatus int
		wantCalled bool
	}{
		{"kalit yoq", "", http.StatusUnauthorized, false},
		{"togri kalit", "key-abc", http.StatusOK, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			calledNext = false
			req := httptest.NewRequest("GET", "/books", nil)
			if tt.apiKey != "" {
				req.Header.Set("X-API-Key", tt.apiKey)
			}
			rec := httptest.NewRecorder()
			handler(rec, req)
			if rec.Code != tt.wantStatus {
				t.Errorf("status = %d, kutilgan %d", rec.Code, tt.wantStatus)
			}
			if calledNext != tt.wantCalled {
				t.Errorf("calledNext = %v, kutilgan %v", calledNext, tt.wantCalled)
			}
		})
	}
}

next — HAQIQIY BookStore yoki JSON javob YOZMAYDI, u FAQAT calledNext = true deb BELGILAYDI. Bu — MIDDLEWARE'ga xos test naqshi: biz createHandler yoki getHandlerNING to'g'ri ishlashini emas, requireAPIKeyNING O'ZI to'g'ri ishlashini ("ruxsat bo'lmasa next chaqirilmasin", "ruxsat bo'lsa chaqirilsin") sinaymiz. Agar next chaqirilgan bo'lsa-yu, lekin STATUS kutilganidan farq qilsa — bu middleware muammosi EMAS, nextNING o'ZI muammo, deb ANIQ ajratish mumkin.

calledNext — ikkita AJRALIB turadigan narsani BIR VAQTDA tekshiradi: (1) status kod TO'G'RImi, (2) next CHAQIRILDIMI yoki YO'Qmi. Faqat statusni tekshirish YETARLI EMAS: masalan middleware xato bilan HAM 200 qaytarib, HAM nextni chaqirmasligi mumkin — calledNext buni FOSH qiladi.

>_ Exercise

NOTO'G'RI (lekin BO'SH bo'lmagan) kalit holatini ham jadvalga qo'shing.

  • tests jadvaliga {"notogri kalit", "wrong", http.StatusUnauthorized, false} qatorini qo'shing
  • BOSHQA hech narsani o'zgartirmang

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Middleware'ni ALOHIDA sinash — HAQIQIY biznes handler o'rniga, oddiy "spy" (kuzatuvchi) funksiya bilan, middleware'ning FAQAT o'ziga xos xatti-harakatini (chaqirilishi yoki chaqirilmasligi) TEKSHIRISHGA imkon beradi.

NEXT UP

Putting It All Together: Wiring the Full API