कंडीशन और पाथ कवरेज

Condition coverage किसी decision के अंदर देखता है। Decision account.active && (amount <= account.dailyLimit || otpOk) में तीन atomic conditions हैं, यानी ऐसे Boolean expressions जिनके अंदर && या || नहीं होता। Branch coverage पूछता है कि पूरा decision true और false हुआ या नहीं; condition coverage पूछता है कि हर condition भी true और false हुई या नहीं। Path coverage पूरे function को देखता है: क्या entry से exit तक का हर रास्ता चलाया गया?

ये दोनों पिछले lessons के statement और branch coverage से आगे जाते हैं, और दोनों में से कोई भी हर जगह 100% पर व्यावहारिक नहीं। असली skill है risky logic के लिए सही subset चुनना और यह बताना कि आपने कौन-सा चुना।

यह क्यों ज़रूरी है

किसी decision में कितनी भी conditions हों, दो tests से उसका branch coverage पूरा हो जाता है। मान लीजिए developer brackets भूल जाता है: account.active && amount <= account.dailyLimit || otpOk। && की precedence || से ज़्यादा है, इसलिए अब one-time password (OTP) confirm करने वाला blocked account भी transfer approve करवा लेता है। अगर branch coverage के दो tests सब true और सब false हों, तो दोनों versions एक जैसे results देते हैं और defect निकल जाता है।

गलत operators, छूटे brackets और बेअसर conditions compound decisions के typical defects हैं, और अक्सर उन्हीं rules में होते हैं जो पैसे और access तय करते हैं। Condition-level criteria थोड़े-से combinations चुनते हैं जो decision पर हर condition का असर जाँचते हैं, और ये defects वहीं दिखते हैं; हर combination टेस्ट करने की ज़रूरत नहीं पड़ती।

Conditions, decisions और condition coverage

पिछले lesson की तरह, decision code का वह point है जहाँ वह outcomes में से चुनता है, जैसे if या loop की condition। Conditions उसके अंदर के Boolean expressions हैं; ISTQB glossary में atomic condition वह condition है जिसमें कोई logical operator नहीं होता। नीचे के function में एक decision है जिसमें तीन atomic conditions हैं: A है account.active, B है amount <= account.dailyLimit और C है otpOk।

Condition coverage नापता है कि tests ने कौन-से condition outcomes, यानी हर atomic condition का true और false, exercise किए। इसमें branch coverage शामिल नहीं। दो tests, limit से ऊपर बिना OTP वाला active account (A true, B false, C false) और limit के अंदर OTP वाला blocked account (A false, B true, C true), 100% condition coverage देते हैं, फिर भी दोनों transfers reject होते हैं और APPROVED कभी नहीं चलता।

  • Condition/decision coverage (जिसे decision condition coverage भी कहते हैं) यह कमी भरता है: इसमें हर condition outcome और हर decision outcome ज़रूरी है।
  • Short-circuit evaluation (ISTQB glossary में short-circuiting): JavaScript, Java और C# में && और || result पता चलते ही रुक जाते हैं (Python के and और or भी): A false हो तो B और C evaluate ही नहीं होतीं। यह lesson tests truth table पर design करता है, पर run time पर ऊपर वाला blocked account test B और C को evaluate ही नहीं करता, इसलिए conditions नापने वाला tool उनके true outcomes नहीं गिनेगा। Tools में फ़र्क भी है: कुछ coverage tools हर operand को branch मानते हैं, कुछ सिर्फ़ पूरे decisions या lines नापते हैं; condition coverage report करने से पहले अपना tool जाँचें।
 1  function reviewTransfer(account: Account, amount: number, otpOk: boolean) {
 2    if (account.active && (amount <= account.dailyLimit || otpOk)) {
 3      return 'APPROVED';
 4    }
 5    return 'REJECTED';
 6  }

Worked example: condition coverage से MC/DC तक

Requirement: "Daily limit के अंदर का transfer approve होता है अगर account active है। Limit से ऊपर उसके लिए confirmed OTP चाहिए। Blocked accounts के transfers हमेशा reject होते हैं।" तीन conditions से 2 × 2 × 2 = 8 combinations बनते हैं: इन्हें business rules वाले lesson की तरह truth table में लिखें, requirement से लिए expected decision के साथ।

Modified condition/decision coverage (MC/DC) माँगता है कि हर condition अकेले decision बदलती दिखे। आम तरीका है independence pair: दो tests जो सिर्फ़ उसी condition में अलग हों और अलग decisions दें। B का pair खोजने के लिए A और C को स्थिर रखें, B को पलटें और देखें कि decision बदलता है या नहीं: A true और C false होने पर rows 2 और 4 true और false देती हैं। Aviation standard DO-178C अपने सबसे critical software level, Level A, के लिए MC/DC ज़रूरी करता है।

A && (B || C) की truth table: rows 4 और 5 पूरा condition coverage देती हैं पर दोनों में decision false है, rows 1 और 8 condition/decision coverage देती हैं, चुना गया MC/DC set rows 2, 3, 4 और 7 है, और multiple condition coverage को सारी 8 चाहिए।
Row · A B CDecisionCondition coverage2 testsCondition/decision coverage2 testsMC/DC4 testsMultiple condition coverage8 tests
1T T TTइस test set में नहींtestइस test set में नहींtest
2T T FTइस test set में नहींइस test set में नहींB (4 के साथ) दिखाती हैtest
3T F TTइस test set में नहींइस test set में नहींA (7 के साथ), C (4 के साथ) दिखाती हैtest
4T F FFtestइस test set में नहींB (2 के साथ), C (3 के साथ) दिखाती हैtest
5F T TFtestइस test set में नहींइस test set में नहींtest
6F T FFइस test set में नहींइस test set में नहींइस test set में नहींtest
7F F TFइस test set में नहींइस test set में नहींA (3 के साथ) दिखाती हैtest
8F F FFइस test set में नहींtestइस test set में नहींtest
  • वह combination जिसे यह criterion टेस्ट करता है
  • Row 7, limit से ऊपर OTP वाला blocked account: वह test जो छूटे brackets पकड़ता है

A = account.active, B = amount <= account.dailyLimit, C = otpOk। T: true, F: false; decision T का मतलब है transfer approve हुआ।

  • Condition coverage: rows 4 और 5, दोनों में decision false। Condition/decision coverage: rows 1 और 8।
  • MC/DC: rows 2, 3, 4 और 7। B को rows 2 और 4 दिखाती हैं, C को 3 और 4, A को 3 और 7। यानी 3 conditions के लिए 4 tests: MC/DC को हमेशा conditions की संख्या से कम से कम एक test ज़्यादा चाहिए।
  • A के लिए rows 2 और 6 भी चल सकती थीं। 3 और 7 चुनें: row 7, यानी limit से ऊपर OTP वाला blocked account, छूटे brackets वाला defect पकड़ती है। जब criterion विकल्प दे, risk के आधार पर चुनें।
  • Multiple condition coverage: सारी 8 rows। हर condition के साथ यह दोगुना होता है; 10 conditions यानी 1,024 combinations।
पाठ संस्करण
Decision: A && (B || C)
A = account.active    B = amount <= account.dailyLimit    C = otpOk

Row   A  B  C   Decision   MC/DC independence pairs
 1    T  T  T   T
 2    T  T  F   T          B: rows 2 and 4
 3    T  F  T   T          C: rows 3 and 4,  A: rows 3 and 7
 4    T  F  F   F          B: rows 2 and 4,  C: rows 3 and 4
 5    F  T  T   F
 6    F  T  F   F
 7    F  F  T   F          A: rows 3 and 7
 8    F  F  F   F

Condition coverage            rows 4, 5          decision never T
Condition/decision coverage   rows 1, 8
MC/DC                         rows 2, 3, 4, 7
Multiple condition coverage   all 8 rows

आज़माएँ: डिसीज़न टेबल जनरेटर

Path coverage, और loops के साथ paths बेकाबू क्यों हो जाते हैं

Path code में entry से exit तक का एक रास्ता है; path coverage पूछता है कि tests ने हर रास्ता चलाया या नहीं। Paths गुणा होते जाते हैं: लगातार तीन if statements के 8 paths हैं, जबकि उनकी सारी branches दो tests से cover हो सकती हैं।

Loops कहीं ज़्यादा बुरे हैं, क्योंकि iterations की हर संख्या एक अलग path है। cartTotal में हर item दो में से एक रास्ता लेता है, इसलिए n items वाले cart के 2^n paths हैं: 20 items वाले भरे cart के 1,048,576, और कुल 2,097,151। बिना upper limit वाले loop के paths अनगिनत हैं। कुछ paths infeasible भी होते हैं: उनकी conditions आपस में टकराती हैं, इसलिए कोई input उन्हें नहीं चला सकता।

  • Loops के लिए iteration count पर boundary values लगाएँ: शून्य, एक, एक typical संख्या और maximum (यहाँ 0, 1, 5 और 20 items), और items जोड़ते समय 21 भी, जिसे cart को refuse करना चाहिए।
  • Paths की सोच ऐसे defects पकड़ती है जिन्हें रास्तों का कोई क्रम चाहिए, जैसे एक iteration से बची state जो अगली iteration बिगाड़ दे।
 1  function cartTotal(items: Item[]): number {   // a cart holds 0 to 20 items
 2    let total = 0;
 3    for (const item of items) {
 4      if (item.onSale) {
 5        total = total + item.salePrice;
 6      } else {
 7        total = total + item.price;
 8      }
 9    }
10    return total;
11  }

Items in cart     Paths
0                 1
1                 2
2                 4
3                 8
20                1,048,576
0 to 20           2,097,151 in total

आज़माएँ: बाउंड्री वैल्यू जनरेटर

Basis paths और cyclomatic complexity

Basis path testing, जो NIST SP 500-235 के structured testing method का मूल है, paths को संभालने लायक रखता है। Cyclomatic complexity, v(G), किसी function के control flow graph से गुज़रने वाले linearly independent paths की अधिकतम संख्या है: v(G) = edges − nodes + 2, जहाँ edges graph की branches हैं। जब हर decision दो-तरफ़ा हो, तो यह decisions की संख्या जमा एक के बराबर होती है। Basis set ऐसे v(G) paths हैं जिन्हें जोड़कर बाकी हर path बनाया जा सकता है।

cartTotal में दो decisions हैं, loop और if, इसलिए v(G) = 3, और तीन tests एक basis set बनाते हैं: खाली cart, एक regular item और एक sale item। Basis set पूरा branch coverage पक्का करता है, हर combination नहीं: यह systematic minimum है, पूरा path coverage नहीं।

  • सिर्फ़ if गिनें तो reviewTransfer का v(G) = 2 है। NIST SP 500-235 हर short-circuit && और || को भी decision गिनता है, क्योंकि हर एक बाकी expression को छोड़ सकता है, इसलिए यह 4 होता है; ESLint का complexity rule भी इन्हें गिनता है। Tools अलग हो सकते हैं, इसलिए figures की तुलना सिर्फ़ एक ही tool से करें।
  • ऊँचे v(G) को signal मानें: ऐसे function को बहुत tests चाहिए और उसे समझना मुश्किल है, इसलिए वह गहरे review या refactoring के लायक है।

आम गलतियाँ

  • 100% condition coverage को "हर decision दोनों तरफ़ गया" समझ लेना।
  • a && (b || c) जैसे compound decision को सिर्फ़ एक बार true और एक बार false टेस्ट करना, जिससे गलत operator या छूटे brackets निकल जाते हैं।
  • यह मान लेना कि test ने वह condition exercise की जिसे short-circuit evaluation ने छोड़ दिया।
  • Loops वाले code में basis paths और चुने हुए iteration counts की बजाय 100% path coverage का लक्ष्य रखना।
  • असंभव combinations या infeasible paths को कारण के साथ दर्ज करने की बजाय gaps के रूप में report करना।
  • सबसे risky combination टेस्ट करने वाले pair की बजाय MC/DC pairs mechanically चुनना।

QA का नज़रिया

Condition-level criteria payments, permissions और eligibility जैसे high-risk logic के लिए इस्तेमाल करें। Reviews में developer से compound decisions समझाने को कहें। Truth table को test design में रखें, असंभव rows को कारण के साथ चिह्नित करें, और चुनी गई rows को data-driven test cases में बदलें जिनके expected results requirement से हों।

Reports में criterion और scope बताएँ: "transfer approval rule: MC/DC 4 tests से"। ऊँची cyclomatic complexity या बहुत conditions वाला decision जल्दी उठाएँ: इससे पता चलता है कि logic को कितने tests चाहिए, और यह code को पहले सरल करने की वजह भी हो सकती है।

अभ्यास

Age rule के लिए MC/DC tests डिज़ाइन करें

आपका काम

Requirement: "18 साल या उससे ज़्यादा उम्र के लोग account खोल सकते हैं। 13 से 17 साल के लोगों को माता-पिता की सहमति (parent consent) चाहिए। 13 साल से कम उम्र का कोई account नहीं खोल सकता।" नीचे developer का function और उसके दो unit tests हैं, जो 100% branch coverage तक पहुँचते हैं।

असली उम्रों के साथ condition-level tests डिज़ाइन करें और पता करें कि unit tests से क्या छूटा।

सामग्री
 1  function canOpenAccount(age: number, parentConsent: boolean): boolean {
 2    if (age >= 18 || (parentConsent && age > 13)) {
 3      return true;
 4    }
 5    return false;
 6  }

Unit tests                         Expected   Result
U1  canOpenAccount(25, true)       true       passed
U2  canOpenAccount(9, false)       false      passed
चरण
  1. Line 2 की atomic conditions के नाम लिखें और असंभव rows के बिना truth table बनाएँ।
  2. हर condition का independence pair खोजें और pairs को मिलाकर सबसे छोटा MC/DC set बनाएँ।
  3. Requirement की boundaries पर उम्रें चुनें, expected results उसी से लें।
  4. Tests trace करें: कौन-सा fail होता है, और U1 व U2 ने क्या कभी नहीं जाँचा?
मॉडल उत्तर दिखाएँ
मॉडल उत्तर

A है age >= 18, B है parentConsent, C है age > 13; decision है A || (B && C)। A true और C false असंभव है (18 या ज़्यादा की हर उम्र 13 से बड़ी है), इसलिए 8 में से 6 combinations बचते हैं।

हर row को A B C के क्रम में लिखें: A को TFT (true) और FFT (false) दिखाती हैं, B को FTT और FFT, C को FTT और FTF। सबसे छोटा MC/DC set है TFT, FFT, FTT और FTF: चार tests।

उम्रें: 18 बिना consent → allowed; 17 बिना consent → refused; 17 consent के साथ → allowed; 12 consent के साथ → refused। Boundary value analysis इसमें 13 consent के साथ → allowed जोड़ता है।

यह test fail होता है: 13 > 13 false है, इसलिए code 13 को 12 वाली row में ही रखता है और वह account refuse करता है जिसे requirement allow करती है। Line 2 का off-by-one defect report करें; fix है age >= 13।

U1 और U2 100% branch coverage तक पहुँचे, पर U1 में अकेले उम्र ने result तय किया और U2 में consent था ही नहीं, इसलिए consent rule कभी टेस्ट नहीं हुआ। MC/DC ने छूटे combinations दिखाए; boundary value analysis ने वह value चुनी जिसने defect पकड़ा।

अक्सर पूछे जाने वाले सवाल

क्या MC/DC में decision coverage शामिल है?

हाँ, उन decisions के लिए जिन पर इसे लगाया गया: हर independence pair decision को एक बार true और एक बार false दिखाता है। उन decisions के बाहर के code के बारे में, या जो behaviour कभी implement ही नहीं हुआ उसके बारे में, यह कुछ नहीं बताता।

मुझे कौन-सा criterion इस्तेमाल करना चाहिए?

Branch coverage को baseline बनाएँ। High-risk rules के compound decisions के लिए condition/decision coverage या MC/DC जोड़ें। जब decision में दो या तीन conditions हों, multiple condition coverage किफ़ायती है। पूरा path coverage सिर्फ़ बिना loops वाले छोटे functions में ठीक है; बाकी जगह एक basis set और ज़रूरी iteration counts टेस्ट करें।

क्या cyclomatic complexity हाथ से निकालनी पड़ती है?

शायद ही कभी। Static analysis tools और linters इसे हर function के लिए निकालते हैं; उदाहरण के लिए ESLint का complexity rule आपकी तय की गई limit से ऊपर वाले हर function को flag करता है। फिर भी किसी छोटे function के लिए एक बार हाथ से निकालना यह समझने में मदद करता है कि यह संख्या क्या गिनती है और tools अलग-अलग नतीजे क्यों दे सकते हैं।

अगर मैं हर path cover कर लूँ, तो क्या function पूरी तरह टेस्ट हो गया?

नहीं। एक path किसी data के साथ pass और दूसरे के साथ fail हो सकता है, जैसे कोई division जो सिर्फ़ किसी value के शून्य होने पर fail होता है, और जो requirement कभी implement ही नहीं हुई उसका कोई path होता ही नहीं। Path coverage code से गुज़रने वाले रास्ते नापता है, results की correctness नहीं।

संदर्भ

  • ISTQB GlossaryISTQBटेस्टिंग शब्दों की मानक परिभाषाएँ — टेस्ट केस, रिग्रेशन टेस्टिंग, सेवेरिटी, प्रायोरिटी, बाउंड्री वैल्यू एनालिसिस आदि।
  • NIST SP 500-235: Structured Testing: A Testing Methodology Using the Cyclomatic Complexity MetricNIST · 1996Structured (basis path) testing: McCabe की cyclomatic complexity से टेस्ट करने के लिए स्वतंत्र paths का basis set निकालना — statement और branch coverage से अधिक गहन।
  • ISTQB Certified Tester Foundation Level (CTFL) v4.0ISTQB · 2023सॉफ़्टवेयर टेस्टिंग का फ़ाउंडेशन पाठ्यक्रम: टेस्ट स्तर और प्रकार, टेस्ट डिज़ाइन तकनीकें, टेस्ट प्रबंधन और टूल।

Mutqan tools से अभ्यास करें

conditions और actions से decision table बनाएँ, सभी rule संयोजन जनरेट करें और असंभव संयोजनों को समेट दें।

टेस्ट डिज़ाइन

और गहराई से

इस topic में आपकी प्रगति

QA रोडमैप का हिस्सा