مرکزی مواد پر جائیں
ماڈیول 9 · سبق 2 از 5کورس میں 42/50~14 min
ماڈیول اسباق (2/5)

ٹیبل پر مبنی ٹیسٹ

ٹیبل پر چلنے والے ٹیسٹ گو کا محاوراتی نمونہ ہیں: N الگ TestThisSpecificCase فنکشنز لکھنے کے بجائے، آپ کیسز کے ٹکڑوں کا اعلان کرتے ہیں اور اعادہ کرتے ہیں۔ ایک دعویٰ بلاک ہے، اور ٹیسٹ ڈیٹا کو منطق سے الگ کر دیا گیا ہے۔

بیس پیٹرن

Go
func TestAbs(t *testing.T) {
    cases := []struct {
        name string
        in   int
        want int
    }{
        {"pos", 3, 3},
        {"neg", -3, 3},
        {"zero", 0, 0},
    }
    for _, tc := range cases {
        t.Run(tc.name, func(t *testing.T) {
            if got := Abs(tc.in); got != tc.want {
                t.Errorf("Abs(%d) = %d; voglio %d", tc.in, got, tc.want)
            }
        })
    }
}

تین اجزاء:

  1. گمنام ڈھانچے کا ٹکڑا معمول کے فیلڈز کے ساتھ: name، ان پٹ، متوقع آؤٹ پٹ (اور شاید ایک متوقع غلطی)۔
  2. for _, tc := range cases — عملدرآمد لوپ۔
  3. t.Run(tc.name, func(t *testing.T) { ... }) — ہر کیس اپنے نام کے ساتھ ایک ذیلی ٹیسٹ بن جاتا ہے۔

کیوں t.Run؟

t.Run ایک ذیلی ٹیسٹ بناتا ہے جس میں:

  • انفرادی نام آؤٹ پٹ میں دکھایا گیا ہے: TestAbs/pos, TestAbs/neg, ...
  • اس کا اپنا t *testing.T: ایک معاملے میں ناکامی دوسرے کو نہیں روکتی (جب تک کہ t.Fatal استعمال نہ کیا جائے)۔
  • کمانڈ لائن فلٹرنگ: go test -run TestAbs/neg صرف اسی صورت میں چلتا ہے۔
  • اختیاری ہم آہنگی: متوازی کرنے کے لیے فنک کے اندر t.Parallel() کو کال کریں۔
Bash
go test -v -run TestAbs/neg

متوقع غلطیوں والے کیسز

Go
cases := []struct {
    name    string
    in      string
    want    int
    wantErr bool
}{
    {"ok", "42", 42, false},
    {"bad", "x", 0, true},
}
for _, tc := range cases {
    t.Run(tc.name, func(t *testing.T) {
        got, err := Atoi(tc.in)
        if (err != nil) != tc.wantErr {
            t.Fatalf("err = %v, wantErr = %v", err, tc.wantErr)
        }
        if !tc.wantErr && got != tc.want {
            t.Errorf("got %d, want %d", got, tc.want)
        }
    })
}

لوپ بند ہونے کا نقصان (پری گو 1.22)

Go 1.22 سے پہلے کے ورژنز میں، tc متغیر کو مشترکہ کیا گیا تھا: t.Parallel() کو t.Run کے اندر کال کرنے سے تمام ذیلی ٹیسٹ اسی آخری کیس کے خلاف چلائے گئے۔ طے یہ تھا:

Go
for _, tc := range cases {
    tc := tc // local rebind (pre-1.22)
    t.Run(tc.name, func(t *testing.T) {
        t.Parallel()
        // ...
    })
}

مقدمات کا نام دینا

بہترین طرز عمل:

  • ایک مختصر لیکن اشتعال انگیز نام: "empty input", "too large", "negative"۔
  • اگر آپ -run کے ساتھ آسانی سے فلٹر کرنا چاہتے ہیں تو کوئی خالی جگہ نہیں ہے (یا انڈر سکور استعمال کریں)۔
  • ہمیشہ ایک "خوشی کا راستہ" کیس، ایک "ایج" کیس (صفر، خالی) اور کم از کم ایک غلطی کا کیس شامل کریں۔

مشقیں

ورزش#go.m9.l2.e1
کوششیں: 0لوڈ ہو رہا ہے…

Abs (مثبت، منفی، صفر) کو جانچنے کے لیے 3 کیسز کے ساتھ آباد، ان اور وانٹ فیلڈز کے ساتھ گمنام ڈھانچے کے کیسز سلائس کی وضاحت کریں۔

ایڈیٹر لوڈ ہو رہا ہے…

3 کوششوں کے بعد حل دستیاب ہے۔

ورزش#go.m9.l2.e2
کوششیں: 0لوڈ ہو رہا ہے…

ہر کیس کو نامزد ذیلی ٹیسٹ میں تبدیل کرنے کے لیے t.Run کو tc.name کے ساتھ شامل کریں۔

ایڈیٹر لوڈ ہو رہا ہے…

3 کوششوں کے بعد حل دستیاب ہے۔

Quiz#go.m9.l2.e3
تیار

N علیحدہ ٹیسٹ فنکشنز پر ٹیبل پر چلنے والے پیٹرن کا بنیادی فائدہ کیا ہے؟

Go
for _, tc := range cases {
  t.Run(tc.name, func(t *testing.T) { ... })
}
جواب کے اختیارات