পাঠ ০৪ · ৫৭-এর মধ্যে · মডিউল ১
Home / Courses / Software Testing & Quality Assurance / সাতটি মূলনীতি

সফটওয়্যার টেস্টিং-এর সাতটি মূলনীতি

The seven principles of software testing
৯ মিনিট পড়া শুরু · Beginner Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • টেস্টিং নিয়ে সাতটি ব্যাপকভাবে স্বীকৃত সাধারণ ধারণা ও প্রতিটির ব্যবহারিক তাৎপর্য
  • "Pesticide paradox" ধারণাটি সত্যিকারের চলমান কোড দিয়ে যাচাই করা
  • কেন টেস্টিং সবসময় context-dependent — একটি ব্যাংকিং অ্যাপ ও একটি গেম আলাদাভাবে টেস্ট করা হয়
  • "বাগমুক্ত মানেই ব্যবহারযোগ্য নয়" — absence-of-errors fallacy বোঝা

১ · সাতটি মূলনীতি

নিচের সাতটি ধারণা সফটওয়্যার টেস্টিং সাহিত্যে দশকের পর দশক ধরে ব্যাপকভাবে শেখানো, সাধারণীকৃত (paraphrased) ধারণা — এগুলো কোনো একটি নির্দিষ্ট সিলেবাস থেকে হুবহু নেওয়া নয়, বরং টেস্টিং পেশায় বহুল-স্বীকৃত সাধারণ জ্ঞান।

নীতি ১ · উপস্থিতি, অনুপস্থিতি নয়
টেস্টিং বাগের উপস্থিতি দেখাতে পারে, কিন্তু কখনোই প্রমাণ করতে পারে না যে কোনো বাগ নেই (L01-এ বিস্তারিত)।
নীতি ২ · Exhaustive টেস্টিং অসম্ভব
সব সম্ভাব্য ইনপুট ও পরিস্থিতির প্রতিটি কম্বিনেশন টেস্ট করা বাস্তবে অসীম সময় লাগবে — তাই ঝুঁকি ও গুরুত্ব বিবেচনা করে টেস্ট বেছে নিতে হয় (M2-এ কৌশল)।
নীতি ৩ · আগে টেস্টিং সস্তা
যত আগে টেস্টিং শুরু হয়, তত কম খরচ ও সময় লাগে বাগ ঠিক করতে (L03-এ বিস্তারিত গণনাসহ)।
নীতি ৪ · Defect clustering
বাগ সাধারণত কোডবেসের একটি ছোট অংশে ক্লাস্টার আকারে জমা হয় (Pareto-ধরনের প্রবণতা) — সেই অংশে অতিরিক্ত মনোযোগ কার্যকর।
নীতি ৫ · Pesticide paradox
একই টেস্ট বারবার অপরিবর্তিতভাবে চালালে একসময় নতুন বাগ ধরা বন্ধ হয়ে যায় — টেস্ট স্যুটকে নিয়মিত পর্যালোচনা ও সম্প্রসারণ করতে হয় (নিচে কোডসহ)।
নীতি ৬ · Context-dependent
টেস্টিং প্রজেক্টের ধরন অনুযায়ী ভিন্ন হয় — একটি ব্যাংকিং অ্যাপ ও একটি ক্যাজুয়াল গেম একই কৌশলে টেস্ট করা উচিত নয়।
নীতি ৭ · Absence-of-errors fallacy
একটি সফটওয়্যার শূন্য বাগ নিয়েও ব্যর্থ হতে পারে, যদি এটি ব্যবহারকারীর প্রকৃত প্রয়োজন পূরণ না করে — বাগমুক্ত হওয়াই যথেষ্ট নয়।

২ · Pesticide Paradox বাস্তবে দেখা

নীতি ৫ বলে — কীটনাশক (pesticide) বারবার একইভাবে ব্যবহার করলে পোকামাকড় ধীরে ধীরে তার প্রতি প্রতিরোধ গড়ে তোলে; একইভাবে, একটি ফিক্সড টেস্ট স্যুট বারবার অপরিবর্তিতভাবে চালালে সেটি নতুন কোনো বাগ ধরতে পারে না, কারণ কোড বা টেস্ট কোনোটিই বদলাচ্ছে না। নিচের কোড সেলে একটি ছোট্ট average() ফাংশন আছে — প্রথমে একটি ৩-টেস্টের ফিক্সড স্যুট তিনবার চালিয়ে দেখানো হয়েছে ফলাফল প্রতিবারই হুবহু একই, তারপর একটি নতুন, আগে-কখনো-না-টেস্ট-করা এজ-কেস (খালি লিস্ট) টার্গেট করা একটি টেস্ট যোগ করে দেখানো হয়েছে সেটি একটি প্রকৃত বাগ ধরে ফেলে।

Python
import unittest

def average(numbers):
    return sum(numbers) / len(numbers)

class AverageTestsOriginalSuite(unittest.TestCase):
    def test_positive_numbers(self):
        self.assertEqual(average([2, 4, 6]), 4)

    def test_negative_numbers(self):
        self.assertEqual(average([-2, -4, -6]), -4)

    def test_mixed_numbers(self):
        self.assertEqual(average([1, 2, 3, 4]), 2.5)

print("=== ১ম বার — মূল টেস্ট স্যুট চালানো ===")
suite = unittest.TestLoader().loadTestsFromTestCase(AverageTestsOriginalSuite)
unittest.TextTestRunner(verbosity=2).run(suite)

print("\n=== ২য় বার — একই টেস্ট স্যুট, কোডে কোনো পরিবর্তন হয়নি ===")
suite = unittest.TestLoader().loadTestsFromTestCase(AverageTestsOriginalSuite)
unittest.TextTestRunner(verbosity=2).run(suite)

print("\n=== ৩য় বার — আবারও একই টেস্ট স্যুট ===")
suite = unittest.TestLoader().loadTestsFromTestCase(AverageTestsOriginalSuite)
unittest.TextTestRunner(verbosity=2).run(suite)

print("\nলক্ষ্য করুন তিনবারই ফলাফল হুবহু একই (৩টি টেস্ট পাস) — কোড অপরিবর্তিত থাকায় একই টেস্ট বারবার চালিয়ে নতুন কোনো তথ্য পাওয়া যায়নি। এটাই pesticide paradox।")

class AverageTestsNewEdgeCase(unittest.TestCase):
    def test_empty_list_should_raise_value_error(self):
        # স্পেসিফিকেশন: খালি লিস্ট দিলে average() একটি স্পষ্ট ValueError দেখানো উচিত, ক্র্যাশ করা উচিত না
        with self.assertRaises(ValueError):
            average([])

print("\n=== নতুন এজ-কেস-টার্গেটেড টেস্ট — খালি লিস্ট (আগে কখনো টেস্ট করা হয়নি) ===")
new_suite = unittest.TestLoader().loadTestsFromTestCase(AverageTestsNewEdgeCase)
unittest.TextTestRunner(verbosity=2).run(new_suite)

    
লক্ষ্য করুন নতুন টেস্টটি FAIL নয়, বরং ERROR হিসেবে রিপোর্ট হয় — কারণ assertRaises(ValueError) শুধু ValueError-ই আশা করছিল, কিন্তু average([]) প্রকৃতপক্ষে ZeroDivisionError রেইজ করে (যেহেতু len([]) শূন্য, এবং শূন্য দিয়ে ভাগ করা হচ্ছে)। assertRaises শুধু নির্দিষ্ট টাইপের এক্সসেপশনই ধরে; অন্য টাইপের অপ্রত্যাশিত এক্সসেপশন টেস্ট মেথডের বাইরে বেরিয়ে আসে এবং unittest সেটিকে "error" হিসেবে গণনা করে। তবু এই ফলাফল স্পষ্টভাবে প্রমাণ করে ফাংশনটির একটি প্রকৃত সমস্যা আছে — মূল ৩-টেস্টের ফিক্সড স্যুট এই সমস্যাটি কখনো খুঁজে পায়নি, কারণ তারা কখনো খালি লিস্ট দিয়ে টেস্ট করেনি। এটাই দেখায় কেন টেস্ট স্যুটকে সময়ের সাথে নতুন এজ-কেস দিয়ে সম্প্রসারণ করা জরুরি (pesticide paradox এড়াতে)।
মূল কথা · Key takeaway

এই সাতটি নীতি একসাথে টেস্টিং সম্পর্কে বাস্তবসম্মত প্রত্যাশা তৈরি করে — টেস্টিং কখনো "সম্পূর্ণ নিশ্চয়তা" দেয় না (নীতি ১, ২, ৭), কিন্তু স্মার্টভাবে ডিজাইন করলে (ঝুঁকি-ভিত্তিক নির্বাচন, ক্লাস্টার-অ্যাওয়্যার ফোকাস, নিয়মিত টেস্ট-স্যুট আপডেট) অনেক বেশি কার্যকর হয় (নীতি ৪, ৫)। M2 মডিউলে আমরা দেখব কীভাবে ইকুইভ্যালেন্স পার্টিশনিং ও বাউন্ডারি ভ্যালু অ্যানালাইসিসের মতো টেকনিক নীতি ২-কে ব্যবহারিকভাবে সামলায় — সব ইনপুট নয়, বরং স্মার্টভাবে বেছে নেওয়া প্রতিনিধিত্বমূলক ইনপুট টেস্ট করে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ নীতি ১ (উপস্থিতি, অনুপস্থিতি নয়) এবং নীতি ২ (exhaustive টেস্টিং অসম্ভব) — এই দুটি নীতি একে অপরের সাথে কীভাবে সম্পর্কিত?

নীতি ২ আসলে নীতি ১-এর মূল কারণ। যেহেতু সব সম্ভাব্য ইনপুট ও পরিস্থিতি টেস্ট করা বাস্তবে অসম্ভব (নীতি ২), তাই একটি টেস্ট স্যুট কখনো নিশ্চিতভাবে বলতে পারে না যে কোনো বাগ নেই — এটি শুধু বলতে পারে যতগুলো পরিস্থিতি টেস্ট করা হয়েছে সেগুলোতে কোনো বাগ পাওয়া যায়নি (নীতি ১)। একটি ছাড়া অন্যটি বোঝা কঠিন।

প্র ০২ কোড সেলে ১ম, ২য়, ৩য় বার একই টেস্ট স্যুট চালিয়ে হুবহু একই ফলাফল পাওয়া গেল। এর মানে কি এই যে average() ফাংশনটি নিখুঁত, নাকি অন্য কিছু বোঝায়?

না, এর মানে ফাংশনটি নিখুঁত তা নয়। এর মানে শুধু এটাই যে যে তিনটি পরিস্থিতি টেস্ট করা হয়েছে (পজিটিভ, নেগেটিভ, মিশ্র সংখ্যা) সেগুলোতে ফাংশনটি সঠিক আচরণ করছে। ঠিক পরের ধাপেই দেখা গেল একটি সম্পূর্ণ ভিন্ন ইনপুট (খালি লিস্ট) একটি প্রকৃত, আগে-অনাবিষ্কৃত বাগ প্রকাশ করে — এটাই নীতি ১-এর বাস্তব প্রমাণ।

প্র ০৩ নীতি ৬ (context-dependent) অনুযায়ী একটি ব্যাংকিং অ্যাপ এবং একটি ক্যাজুয়াল মোবাইল গেমের টেস্টিং স্ট্র্যাটেজি ভিন্ন হওয়া উচিত কেন? প্রতিটির জন্য একটি বিশেষভাবে গুরুত্বপূর্ণ টেস্টিং দিক উল্লেখ করুন।

একটি ব্যাংকিং অ্যাপে আর্থিক হিসাব-নিকাশের নির্ভুলতা, ডেটা সিকিউরিটি ও অডিট-ট্রেইল অত্যন্ত গুরুত্বপূর্ণ (M9-এ সিকিউরিটি টেস্টিং বিস্তারিত) — এখানে বাগের সহনশীলতা প্রায় শূন্য। একটি ক্যাজুয়াল গেমে পারফরম্যান্স/ফ্রেম-রেট ও বিভিন্ন ডিভাইসে ব্যবহারকারীর অভিজ্ঞতা বেশি গুরুত্বপূর্ণ (M8-এ পারফরম্যান্স টেস্টিং), এবং ছোটখাটো কসমেটিক বাগে বেশি সহনশীলতা থাকে, দ্রুত রিলিজ সাইকেল প্রাধান্য পায়। একই কৌশল দুটিতে সমানভাবে প্রযোজ্য নয়।

অনুশীলন

  1. চিন্তা করুন: L01-এর calculate_shipping_cost উদাহরণে ইতিমধ্যে নিচে/সমান/উপরে-থ্রেশহোল্ড টেস্ট করা আছে। নীতি ৫ (pesticide paradox) অনুসরণ করে, ভবিষ্যতে যোগ করা যেতে পারে এমন একটি সম্পূর্ণ নতুন এজ-কেসের কথা ভাবুন যা বর্তমান স্যুট এখনো মিস করতে পারে।

    ভালো প্রার্থী: নেগেটিভ বা শূন্য order_total (যেমন -100 বা 0) — স্পেসিফিকেশনে এই পরিস্থিতি নিয়ে কিছু বলা নেই, তাই এখন পর্যন্ত কোনো টেস্ট এটি যাচাই করেনি। এই ধরনের "স্পেসিফিকেশনে অনুল্লেখিত" ইনপুট প্রায়ই এমন এজ-কেস যেখানে ফিক্সড টেস্ট স্যুট নতুন কিছু ধরতে ব্যর্থ হয়।

  2. পরীক্ষা করুন: উপরের কোড সেলে average() ফাংশনটিকে এভাবে ঠিক করুন — একদম শুরুতে একটি লাইন যোগ করুন যা numbers খালি হলে সরাসরি raise ValueError("average of empty list is undefined") করে — তারপর Run চেপে দেখুন AverageTestsNewEdgeCase এখন পাস করে কি না, এবং মূল তিনটি টেস্টও এখনও পাস করছে কি না।

    হ্যাঁ — এই গার্ড-ক্লজ যোগ করার পর average([]) এখন সঠিকভাবে ValueError রেইজ করবে, তাই AverageTestsNewEdgeCase-এর টেস্টটি "ERROR"-এর বদলে পাস (OK) দেখাবে। মূল তিনটি টেস্টও (পজিটিভ, নেগেটিভ, মিশ্র সংখ্যা) অপরিবর্তিত থাকবে ও পাস করতে থাকবে, কারণ নতুন লাইনটি শুধু খালি লিস্টের ক্ষেত্রেই কার্যকর হয় — এটি একটি রিগ্রেশন-মুক্ত ফিক্সের ভালো উদাহরণ (M5/L22-এ বিস্তারিত)।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • পরবর্তী পাঠ L05 ইকুইভ্যালেন্স পার্টিশনিং — নীতি ২ (exhaustive impossible) সামলানোর প্রথম ব্যবহারিক টেকনিক, M2 মডিউলের শুরু।
  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ টেস্ট ডিজাইন টেকনিক, ইউনিট টেস্টিং, টেস্ট ডাবলস, ইন্টিগ্রেশন টেস্টিং, কভারেজ, অটোমেশন, পারফরম্যান্স ও সিকিউরিটি টেস্টিং, অ্যাডভান্সড টেকনিক ও CI/CD ইন্টিগ্রেশন — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
  • Software Engineering Principles & Git কোর্স সহোদর কোর্স SDLC ও সাধারণ ইঞ্জিনিয়ারিং প্রিন্সিপলের ভিত্তি সেই কোর্সেই তৈরি হয়েছে — এই কোর্স টেস্টিং-এর মূলনীতিগুলো গভীরে নিয়ে যায়।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Programming Languages & Compiler Design, Software Engineering & Git, Theory of Computation, Engineering Economics, Full-Stack Web Frameworks, Mobile App Development, Ethics in Computing & AI Safety ও Software Testing & Quality Assurance — সব এক জায়গায়।
আগের পাঠ
বাগের প্রকৃত খরচ — কেন আগে ধরা সস্তা