GoDasturchi
Testing Handlers: Table-Driven Tests

Testing Handlers: Table-Driven Tests

Handlerlarni testlash: jadval asosidagi testlar

Avtomobil texnik ko'rigidan o'tayotganda, mexanik HAR BIR avtomobilni BIR XIL TEKSHIRUV RO'YXATI (tormoz, chiroq, shina) bo'yicha tekshiradi — har safar YANGI ro'yxat yozib o'tirmaydi. "Professional Go Testing" kursidagi "Table-Driven Tests" darsida ko'rgan bu naqsh, HTTP handler'larni sinashda AYNIQSA foydali: bitta handler ko'plab KIRISH holatiga (to'g'ri, noto'g'ri, chegaraviy) ega bo'ladi, va ularning HAR BIRINI ALOHIDA test yozish o'rniga, BITTA jadval qilib, ustidan bitta sikl bilan yuriladi.

example.go
package main

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

type CreateBookRequest struct {
	Title string  `json:"title"`
	Price float64 `json:"price"`
}

func createHandler(w http.ResponseWriter, r *http.Request) {
	var req CreateBookRequest
	json.NewDecoder(r.Body).Decode(&req)
	if strings.TrimSpace(req.Title) == "" || req.Price <= 0 {
		w.WriteHeader(http.StatusUnprocessableEntity)
		return
	}
	w.WriteHeader(http.StatusCreated)
}

func TestCreateHandler(t *testing.T) {
	tests := []struct {
		name       string
		body       string
		wantStatus int
	}{
		{"togri sorov", `{"title":"Go","price":1000}`, http.StatusCreated},
		{"bosh title", `{"title":"","price":1000}`, http.StatusUnprocessableEntity},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req := httptest.NewRequest("POST", "/books", strings.NewReader(tt.body))
			rec := httptest.NewRecorder()
			createHandler(rec, req)
			if rec.Code != tt.wantStatus {
				t.Errorf("status = %d, kutilgan %d", rec.Code, tt.wantStatus)
			}
		})
	}
}

tests := []struct{...}{...} — HAR BIR test holatini (nomi, kiruvchi so'rov tanasi, kutilgan status) BITTA qatorli struct sifatida belgilaydi. t.Run(tt.name, func(t *testing.T) {...}) — HAR BIR holatni ALOHIDA subtest sifatida ishga tushiradi: agar "bosh title" holati MUVAFFAQIYATSIZ bo'lsa, "togri sorov" HALI ham alohida ko'rinadi va o'z natijasini ko'rsatadi — ular BIR-BIRIGA ta'sir qilmaydi.

Bu naqshning ASOSIY afzalligi: YANGI holat qo'shish uchun YANGI test funksiyasi YOZISH shart emas — jadvalga BITTA qator qo'shish YETARLI. httptest.NewRecorder() — bu darsda ham, "HTTP Testing with httptest" darsidagi kabi, HAQIQIY server ochmasdan handler'ni to'g'ridan-to'g'ri sinash imkonini beradi.

>_ Exercise

Jadvalga YANA bir chegaraviy holat qo'shing.

  • tests jadvaliga {"nol narx", {"title":"Go","price":0}, http.StatusUnprocessableEntity} qatorini qo'shing
  • BOSHQA hech narsani o'zgartirmang — sikl AVTOMATIK ravishda yangi holatni ham sinaydi

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Jadval asosidagi testlar — handler'ning ko'plab kirish/chiqish holatini BITTA jadval va BITTA sikl orqali sinaydi; yangi holat qo'shish uchun test KODI emas, FAQAT jadvalga bitta qator YETARLI.

NEXT UP

Testing Middleware in Isolation

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

Testing Handlers: Table-Driven Tests

Handlerlarni testlash: jadval asosidagi testlar

Avtomobil texnik ko'rigidan o'tayotganda, mexanik HAR BIR avtomobilni BIR XIL TEKSHIRUV RO'YXATI (tormoz, chiroq, shina) bo'yicha tekshiradi — har safar YANGI ro'yxat yozib o'tirmaydi. "Professional Go Testing" kursidagi "Table-Driven Tests" darsida ko'rgan bu naqsh, HTTP handler'larni sinashda AYNIQSA foydali: bitta handler ko'plab KIRISH holatiga (to'g'ri, noto'g'ri, chegaraviy) ega bo'ladi, va ularning HAR BIRINI ALOHIDA test yozish o'rniga, BITTA jadval qilib, ustidan bitta sikl bilan yuriladi.

example.go
package main

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

type CreateBookRequest struct {
	Title string  `json:"title"`
	Price float64 `json:"price"`
}

func createHandler(w http.ResponseWriter, r *http.Request) {
	var req CreateBookRequest
	json.NewDecoder(r.Body).Decode(&req)
	if strings.TrimSpace(req.Title) == "" || req.Price <= 0 {
		w.WriteHeader(http.StatusUnprocessableEntity)
		return
	}
	w.WriteHeader(http.StatusCreated)
}

func TestCreateHandler(t *testing.T) {
	tests := []struct {
		name       string
		body       string
		wantStatus int
	}{
		{"togri sorov", `{"title":"Go","price":1000}`, http.StatusCreated},
		{"bosh title", `{"title":"","price":1000}`, http.StatusUnprocessableEntity},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req := httptest.NewRequest("POST", "/books", strings.NewReader(tt.body))
			rec := httptest.NewRecorder()
			createHandler(rec, req)
			if rec.Code != tt.wantStatus {
				t.Errorf("status = %d, kutilgan %d", rec.Code, tt.wantStatus)
			}
		})
	}
}

tests := []struct{...}{...} — HAR BIR test holatini (nomi, kiruvchi so'rov tanasi, kutilgan status) BITTA qatorli struct sifatida belgilaydi. t.Run(tt.name, func(t *testing.T) {...}) — HAR BIR holatni ALOHIDA subtest sifatida ishga tushiradi: agar "bosh title" holati MUVAFFAQIYATSIZ bo'lsa, "togri sorov" HALI ham alohida ko'rinadi va o'z natijasini ko'rsatadi — ular BIR-BIRIGA ta'sir qilmaydi.

Bu naqshning ASOSIY afzalligi: YANGI holat qo'shish uchun YANGI test funksiyasi YOZISH shart emas — jadvalga BITTA qator qo'shish YETARLI. httptest.NewRecorder() — bu darsda ham, "HTTP Testing with httptest" darsidagi kabi, HAQIQIY server ochmasdan handler'ni to'g'ridan-to'g'ri sinash imkonini beradi.

>_ Exercise

Jadvalga YANA bir chegaraviy holat qo'shing.

  • tests jadvaliga {"nol narx", {"title":"Go","price":0}, http.StatusUnprocessableEntity} qatorini qo'shing
  • BOSHQA hech narsani o'zgartirmang — sikl AVTOMATIK ravishda yangi holatni ham sinaydi

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Jadval asosidagi testlar — handler'ning ko'plab kirish/chiqish holatini BITTA jadval va BITTA sikl orqali sinaydi; yangi holat qo'shish uchun test KODI emas, FAQAT jadvalga bitta qator YETARLI.

NEXT UP

Testing Middleware in Isolation