মূল কন্টেন্টে যান
মডিউল 9 · 2-এর পাঠ 5কোর্সে 42/50~14 min
মডিউল পাঠ (2/5)

টেবিল চালিত পরীক্ষা

টেবিল-চালিত পরীক্ষা হল Go-এর ইডিওম্যাটিক প্যাটার্ন: 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লোড হচ্ছে...

প্রতিটি কেসকে একটি নামযুক্ত সাব-টেস্টে পরিণত করতে tc.name দিয়ে t.Run যোগ করুন।

সম্পাদক লোড হচ্ছে...

সমাধান 3 প্রচেষ্টার পরে উপলব্ধ

Quiz#go.m9.l2.e3
প্রস্তুত

এন পৃথক টেস্ট ফাংশনের তুলনায় টেবিল-চালিত প্যাটার্নের প্রধান সুবিধা কী?

Go
for _, tc := range cases {
  t.Run(tc.name, func(t *testing.T) { ... })
}
উত্তরের বিকল্প