বাউন্ডারি ভ্যালু অ্যানালাইসিস
এই পাঠে যা শিখবেন
- বাউন্ডারি ভ্যালু অ্যানালাইসিস কী এবং কেন এটি ইকুইভ্যালেন্স পার্টিশনিং-এর প্রাকৃতিক পরবর্তী ধাপ
- একটি রেঞ্জ স্পেসিফিকেশন থেকে ছয়টি ক্লাসিক বাউন্ডারি মান প্রোগ্রাম্যাটিকভাবে বের করা
- কেন
>বনাম>=-এর মতো ছোট ভুল ঠিক কিনারাতেই ধরা পড়ে, অন্য কোথাও নয় - Python-এর
unittestদিয়ে একটি সত্যিকারের বাউন্ডারি বাগ ধরে ফেলার সম্পূর্ণ ডেমো
১ · কেন কিনারার মান সবচেয়ে বেশি ঝুঁকিপূর্ণ
কোডে রেঞ্জ-চেক প্রায়ই >, >=, <, <= দিয়ে লেখা
হয় — আর এই অপারেটরগুলোর মধ্যে একটি ভুল বেছে নিলে পুরো রেঞ্জের আচরণ ঠিক থাকলেও শুধু কিনারার এক-দুইটা মানেই
সমস্যা দেখা দেয়। L05-এ আমরা দেখেছি ইকুইভ্যালেন্স পার্টিশনিং একটি পার্টিশন থেকে যেকোনো প্রতিনিধি মান বাছাই
করে — কিন্তু যদি প্রতিনিধি মান কাকতালীয়ভাবে কিনারা থেকে দূরে থাকে (যেমন বয়স ৪০), তাহলে ঠিক ১৮
বা ৬৫-তে থাকা বাগ একেবারেই চোখ এড়িয়ে যাবে। বাউন্ডারি ভ্যালু অ্যানালাইসিস ঠিক এই ফাঁকটাই পূরণ
করে — ইচ্ছাকৃতভাবে কিনারার মান বেছে নিয়ে।
২ · একটি সত্যিকারের বাউন্ডারি বাগ ধরার ডেমো
নিচের qualifies_for_bulk_pricing ফাংশনটির নিয়ম হলো — অর্ডারের quantity ১০ থেকে ১০০-এর মধ্যে
(দুই প্রান্ত সহ) হলে বাল্ক প্রাইসিং প্রযোজ্য। L01-এর calculate_shipping_cost-এর মতোই এখানে
একটি সূক্ষ্ম বাউন্ডারি বাগ লুকিয়ে আছে — এবার একটির বদলে দুই প্রান্তেই। ছয়টি বাউন্ডারি মান প্রোগ্রাম্যাটিকভাবে
তৈরি করে সত্যিকারের unittest দিয়ে চালিয়ে দেখা যাক।
import unittest
MIN_QTY = 10
MAX_QTY = 100
def qualifies_for_bulk_pricing(quantity):
# নিয়ম: quantity 10 থেকে 100 (দুই প্রান্ত সহ) হলে বাল্ক প্রাইসিং প্রযোজ্য
if quantity > MIN_QTY and quantity < MAX_QTY: # বাগ: দুই প্রান্তই ভুলভাবে বাদ পড়ে গেছে
return True
return False
# স্পেসিফিকেশন থেকে প্রোগ্রাম্যাটিকভাবে তৈরি ছয়টি ক্লাসিক বাউন্ডারি মান
BOUNDARY_VALUES = [MIN_QTY - 1, MIN_QTY, MIN_QTY + 1, MAX_QTY - 1, MAX_QTY, MAX_QTY + 1]
print("বাউন্ডারি ভ্যালু যাচাই:")
for qty in BOUNDARY_VALUES:
expected = MIN_QTY <= qty <= MAX_QTY # স্পেসিফিকেশন সরাসরি থেকে প্রত্যাশিত ফলাফল
actual = qualifies_for_bulk_pricing(qty)
status = "PASS" if actual == expected else "FAIL"
print(f" [{status}] quantity={qty} প্রত্যাশিত={expected} পেয়েছে={actual}")
class BulkPricingBoundaryTests(unittest.TestCase):
def test_min_minus_one_rejected(self):
self.assertFalse(qualifies_for_bulk_pricing(9))
def test_min_accepted(self):
self.assertTrue(qualifies_for_bulk_pricing(10))
def test_min_plus_one_accepted(self):
self.assertTrue(qualifies_for_bulk_pricing(11))
def test_max_minus_one_accepted(self):
self.assertTrue(qualifies_for_bulk_pricing(99))
def test_max_accepted(self):
self.assertTrue(qualifies_for_bulk_pricing(100))
def test_max_plus_one_rejected(self):
self.assertFalse(qualifies_for_bulk_pricing(101))
suite = unittest.TestLoader().loadTestsFromTestCase(BulkPricingBoundaryTests)
unittest.TextTestRunner(verbosity=2).run(suite)
quantity=10 এবং quantity=100 — অর্থাৎ ঠিক দুই প্রান্তেই — টেস্ট
ব্যর্থ (FAIL) হয়, মোট ৬টির মধ্যে ২টি ব্যর্থতা। কারণ কোডে লেখা আছে quantity > MIN_QTY ও
quantity < MAX_QTY (কঠোর তুলনা), কিন্তু স্পেসিফিকেশন বলছে "দুই প্রান্ত সহ" —
>= ও <= হওয়ার কথা ছিল। মজার ব্যাপার হলো, যদি আমরা শুধু ইকুইভ্যালেন্স
পার্টিশনিং (L05) ব্যবহার করে ভ্যালিড পার্টিশন থেকে quantity=50-এর মতো একটি মাঝামাঝি মান বাছাই
করতাম, এই বাগ দুটো একেবারেই ধরা পড়ত না — এটাই বাউন্ডারি ভ্যালু অ্যানালাইসিসের আসল মূল্য।
বাউন্ডারি ভ্যালু অ্যানালাইসিস ইকুইভ্যালেন্স পার্টিশনিং-এর পরিপূরক — এটি স্পষ্টভাবে বলে দেয় কোন নির্দিষ্ট
মানগুলো টেস্ট করা সবচেয়ে বেশি লাভজনক (কিনারার মান), শুধু "কোন গ্রুপ থেকে" নয়। min-1, min, min+1,
max-1, max, max+1 — এই ছয়টি মান মনে রাখলেই যেকোনো রেঞ্জ-ভিত্তিক স্পেসিফিকেশনের জন্য একটি শক্তিশালী
বাউন্ডারি টেস্ট সেট তৈরি করা যায়।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ উপরের কোড সেলে ঠিক কোন দুটো লাইনে বাগ আছে, এবং কীভাবে ঠিক করবেন?
বাগটি if quantity > MIN_QTY and quantity < MAX_QTY: লাইনে — দুটো তুলনাই কঠোর
(strict)। ঠিক করতে >-কে >=-এ এবং <-কে <=-এ
পরিবর্তন করতে হবে: if quantity >= MIN_QTY and quantity <= MAX_QTY: — এতে ছয়টি
টেস্টই পাস করবে।
প্র ০২ যদি স্পেসিফিকেশন বলত "quantity ১০-এর বেশি (strictly greater) হলে বাল্ক প্রাইসিং প্রযোজ্য" — অর্থাৎ ১০ নিজে বাদ — তাহলে কি বর্তমান কোডটি বাগমুক্ত হতো?
মিনিমাম প্রান্তের জন্য হ্যাঁ (quantity > 10 তখন সঠিক হতো), কিন্তু ম্যাক্সিমাম প্রান্তের
বাগ (quantity < MAX_QTY বনাম <=) তাতে প্রভাবিত হতো না — সেটি এখনও ভুলই
থাকত, যদি স্পেসিফিকেশন ম্যাক্সিমাম প্রান্তে "দুই প্রান্ত সহ" বলে। এই প্রশ্নটাই দেখায় কেন প্রতিটি প্রান্ত
আলাদাভাবে, তার নিজস্ব স্পেসিফিকেশন অনুযায়ী যাচাই করা জরুরি।
প্র ০৩ বাউন্ডারি ভ্যালু অ্যানালাইসিস কি ইকুইভ্যালেন্স পার্টিশনিং-কে সম্পূর্ণ প্রতিস্থাপন করে, নাকি দুটোই একসাথে দরকার?
দুটোই একসাথে দরকার। ইকুইভ্যালেন্স পার্টিশনিং প্রথমে বলে দেয় ইনপুট ডোমেইনের কোন কোন "গ্রুপ" স্বতন্ত্র আচরণ করে (এখানে কয়টি রেঞ্জ আছে) — বাউন্ডারি ভ্যালু অ্যানালাইসিস তারপর প্রতিটি গ্রুপের কিনারায় ফোকাস করে সবচেয়ে ঝুঁকিপূর্ণ নির্দিষ্ট মানগুলো বের করে। একটি ছাড়া অন্যটি অসম্পূর্ণ একটি টেস্ট স্ট্র্যাটেজি দেয়।
অনুশীলন
-
চিন্তা করুন: একটি ফাংশন আছে যেখানে ডিসকাউন্ট প্রযোজ্য হয় অর্ডার টোটাল ৫০০ থেকে ৫০০০
টাকার মধ্যে হলে (দুই প্রান্ত সহ)। এর ছয়টি বাউন্ডারি মান কী কী হবে?
499 (min-1), 500 (min), 501 (min+1), 4999 (max-1), 5000 (max), 5001 (max+1)— ঠিক উপরের কোড সেলের মতোই গঠন, শুধুMIN_QTY-এর বদলে500ওMAX_QTY-এর বদলে5000বসিয়ে। -
পরীক্ষা করুন: উপরের কোড সেলে
if quantity > MIN_QTY and quantity < MAX_QTY:-কেif quantity >= MIN_QTY and quantity <= MAX_QTY:-এ পরিবর্তন করে Run চেপে দেখুন এখন ছয়টি টেস্টই পাস করে কি না।হ্যাঁ — পরিবর্তনের পর
qualifies_for_bulk_pricing(10)ওqualifies_for_bulk_pricing(100)উভয়েই সঠিকভাবেTrueরিটার্ন করবে, তাই ছয়টি টেস্টই পাস করবে এবং আউটপুটে "OK" দেখাবে, আগের "FAILED (failures=2)"-এর বদলে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পরের পাঠ: ডিসিশন টেবিল টেস্টিং L07 যখন একটির বদলে একাধিক শর্ত একসাথে মিলে ফলাফল ঠিক করে — একটি টেবিল দিয়ে সবগুলো সমন্বয় নিয়মতান্ত্রিকভাবে যাচাই করা।
-
L01-এ ফিরে দেখুন L01
এই পাঠের বাউন্ডারি বাগ ডেমোটি L01-এর
calculate_shipping_costডেমোর সরাসরি সম্প্রসারণ — দুটো পাশাপাশি তুলনা করলে প্যাটার্নটি আরও স্পষ্ট হবে। - কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ টেস্ট ডিজাইন টেকনিক, ইউনিট টেস্টিং, টেস্ট ডাবলস, ইন্টিগ্রেশন টেস্টিং, কভারেজ, অটোমেশন, পারফরম্যান্স ও সিকিউরিটি টেস্টিং, অ্যাডভান্সড টেকনিক ও CI/CD ইন্টিগ্রেশন।