स्टेटमेंट कवरेज

Statement coverage मापता है कि किसी program के executable statements में से कितने, tests के किसी set ने कम से कम एक बार चलाए। Statement testing, यानी इसके पीछे की white-box technique, में coverage items executable statements होते हैं, और आप tests तब तक design करते हैं जब तक वे सब, या उनका तय किया गया हिस्सा, चल न जाएँ।

उदाहरण: एक function में 6 executable statements हैं और आपका इकलौता test उनमें से 5 चलाता है। Statement coverage 5 / 6 = 83% है। छठे statement तक पहुँचने वाला दूसरा test इसे 100% कर देता है: हर statement कम से कम एक बार चल चुका है, और यह criterion बस इतना ही वादा करता है।

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

कोई defect failure तभी पैदा कर सकता है जब उसे रखने वाला code चले। Statement coverage उस code की ओर इशारा करता है जिसे किसी test ने कभी नहीं चलाया, जहाँ कोई defect उन tests में सामने नहीं आ सकता। यह समझाने में सबसे आसान coverage measure भी है।

इसकी कमज़ोरी भी उतनी ही अहम है। 100% बहुत कम tests से हासिल हो सकता है, जो decision outcomes, loop cases और data values को untested छोड़ देते हैं; अगले lesson का विषय branch coverage इससे मज़बूत criterion है। जो tester ठीक-ठीक जानता है कि यह number क्या साबित करता है, वह इससे gaps ढूँढ सकता है, बिना इसे इस बात का सबूत माने कि code अच्छी तरह tested है।

Statement coverage क्या मापता है

ISTQB Foundation syllabus v4.0 के अनुसार statement coverage को ऐसे नापा जाता है: tests द्वारा execute हुए executable statements की संख्या, भाग executable statements की कुल संख्या, percentage के रूप में: statement coverage = statements executed / executable statements × 100%।

Executable statement वह statement है जो program चलने पर कोई action करता है। हर statement एक ही बार गिना जाता है, चाहे उसे कितने भी tests चलाएँ और कोई loop उसे कितनी भी बार दोहराए। 100% पर हर executable statement कम से कम एक बार चल चुका होता है, इसलिए defect वाला statement भी चला है, और इससे ऐसा failure हो सकता है जो defect को दिखा दे। यहाँ "हो सकता है" ही असली बात है, जैसा worked example दिखाता है।

  • गिनें: assignments और value वाले declarations (let fee = 5;), function calls, return और throw, और हर if, switch या loop statement ख़ुद, क्योंकि उसकी condition evaluate करना भी एक action है।
  • हाथ से गिनते समय न गिनें: comments, खाली lines, सिर्फ़ brace वाली lines, function का signature, और सिर्फ़ types वाला code, जैसे TypeScript का interface।
  • कोई statement covered तब है जब कम से कम एक test ने उसे execute किया, चाहे वह test pass हुआ हो या नहीं, और उसने कुछ assert किया हो या नहीं।
  • Tools details में अलग होते हैं: coverage.py execute हुई lines record करता है, और Python की def line module import होते समय चलती है, इसलिए वह covered गिनी जाती है, चाहे कोई test उस function को call न करे। इसलिए percentages की तुलना सिर्फ़ एक ही tool, settings और files के बीच करें।

Worked example: parking fee का function

Requirement: "पहले 30 मिनट parking free है। उसके बाद हर शुरू हुए घंटे के 5.00 SAR लगते हैं। Members आधा देते हैं।" Developer ने नीचे वाला function और दो unit tests, T1 और T2, लिखे; line 4 का Math.ceil ऊपर की ओर round करता है, जिससे "हर शुरू हुआ घंटा" वाला नियम लागू होता है। इसके executable statements lines 2, 3, 4, 6, 7 और 9 हैं; signature और closing brace वाली lines statements नहीं हैं।

parkingFee में 6 executable statements हैं: T1 उनमें से 5 चलाता है (83%) और T2 सभी 6 (100%), फिर भी statement 1 की ग़लत शुरुआती fee किसी भी test को fail नहीं कराती।

parkingFee, उसके दो unit tests और उनकी statement coverage

 1  function parkingFee(minutes, member) {
 2    भाग 1:let fee = 5;
 3    भाग 2:if (minutes > 30) {
 4      भाग 3:fee = Math.ceil((minutes - 30) / 60) * 5;
 5    }
 6    भाग 4:if (member) {
 7      भाग 5:fee = fee / 2;
 8    }
 9    भाग 6:return fee;
10  }

Executable statements: lines 2, 3, 4, 6, 7, 9 (6 in total)

Unit test                  Expected  Actual  Result  Lines run      Statement coverage
T1  parkingFee(90, false)  5         5       passed  2 3 4 6 9      5/6   83%
T2  parkingFee(200, true)  7.5       7.5     passed  2 3 4 6 7 9    6/6  100%
T1 + T2                                              2 3 4 6 7 9    6/6  100%
  • 1–66 coverage items: formula का denominator
  1. 1Statement 1 · line 2T1 और T2 दोनों में चलता है। इसी में defect है, 0 की जगह 5 की शुरुआती fee, पर दोनों tests में line 4 उसे overwrite कर देती है, इसलिए कोई fail नहीं होता।T1 · T2सावधानी
  2. 2Statement 2 · line 3: decisionदोनों tests में चलता है, हर बार outcome true के साथ। इसके false outcome का कोई statement नहीं, इसलिए statement coverage उसे कभी नहीं माँगता।T1 · T2
  3. 3Statement 3 · line 4दोनों tests में चलता है: 90 और 200 मिनट, दोनों 30 से ज़्यादा हैं।T1 · T2
  4. 4Statement 4 · line 6: decisionदोनों tests में चलता है: T1 में false, T2 में true।T1 · T2
  5. 5Statement 5 · line 7सिर्फ़ T2, यानी member वाले test, में चलता है। अकेले T1 से coverage 5 / 6 = 83% है।T2
  6. 6Statement 6 · line 9दोनों tests में चलता है।T1 · T2

Signature और closing brace वाली lines executable statements नहीं हैं, इसलिए formula के किसी भी हिस्से में नहीं गिनी जातीं।

  • T1 parkingFee(90, false) lines 2, 3, 4, 6 और 9 चलाता है और expected के मुताबिक़ 5 लौटाता है। Line 7 नहीं चलती क्योंकि member false है: 5 / 6 = 83%।
  • T2 parkingFee(200, true) सभी छह statements चलाता है: free period के बाद 170 मिनट यानी 3 शुरू हुए घंटे, 15.00 SAR, आधा करके 7.50। T1 और T2 मिलकर 6 / 6 = 100% तक पहुँचते हैं, और अकेला T2 भी पहुँच जाता।
  • Requirement के पहले वाक्य से बना test, T3 parkingFee(20, false), 0 expect करता है और 5 पाता है: line 2 fee को 0 की जगह 5 से शुरू करती है, इसलिए free period का भी charge लग जाता है।
  • Line 2, T1 और T2 दोनों में चली, फिर भी कोई fail नहीं हुआ: हर बार line 4 ने ग़लत value को overwrite कर दिया। Defect तभी दिखता है जब minutes > 30 false हो, और इस outcome का अपना कोई statement नहीं, इसलिए statement coverage ने इसे कभी माँगा ही नहीं। अगले lesson का branch coverage इसे माँगता है।
पाठ संस्करण
 1  function parkingFee(minutes, member) {
 2    let fee = 5;
 3    if (minutes > 30) {
 4      fee = Math.ceil((minutes - 30) / 60) * 5;
 5    }
 6    if (member) {
 7      fee = fee / 2;
 8    }
 9    return fee;
10  }

Executable statements: lines 2, 3, 4, 6, 7, 9 (6 in total)

Unit test                  Expected  Actual  Result  Lines run      Statement coverage
T1  parkingFee(90, false)  5         5       passed  2 3 4 6 9      5/6   83%
T2  parkingFee(200, true)  7.5       7.5     passed  2 3 4 6 7 9    6/6  100%
T1 + T2                                              2 3 4 6 7 9    6/6  100%

100% statement coverage क्या साबित नहीं करता

ISTQB syllabus दो सीमाएँ बताता है: किसी statement को execute करना उसके हर defect को नहीं पकड़ता, जैसे data पर निर्भर defect, और 100% statement coverage यह सुनिश्चित नहीं करता कि सारा decision logic tested है। ये बार-बार आने वाले कुछ रूपों में दिखती हैं:

  • छूटे हुए outcomes: बिना else वाले if का false outcome ऐसा है जिसका अपना कोई statement नहीं। Parking वाला defect वहीं रहता है।
  • Data पर निर्भर defects: average = total / count तब बिना failure के चलता है जब count 3 हो, और 0 होने पर fail होता है या बेमतलब value लौटाता है। दोनों हालात में statement covered है।
  • Loops: किसी simple loop body से एक बार गुज़रना उसके सारे statements cover कर देता है। शून्य बार (खाली list) या कई बार गुज़रना कभी ज़रूरी नहीं होता।
  • Compound conditions: if (gold || total >= 200) एक statement है, जिसे वह test cover कर देता है जिसमें gold true हो, और ज़्यादातर languages में तब दूसरी condition evaluate ही नहीं होती। Condition coverage वाला lesson इस पर लौटता है।

Statement coverage का सही इस्तेमाल

Statement coverage सबसे ज़्यादा काम का एक floor के रूप में है: जिस statement को कोई test नहीं चलाता, वह पक्का blind spot है। Goal के रूप में यह सबसे कम काम का है, क्योंकि इसे बढ़ाने का सबसे सस्ता तरीका ऐसा test है जो code चलाता है और बहुत कम जाँचता है।

  • Requirement-based tests (equivalence partitioning, boundary value analysis) से शुरू करें, coverage नापें, और उसके बाद ही उन statements के लिए tests जोड़ें जो कभी नहीं चले। Parking के minutes को "30 तक" और "30 से ज़्यादा" में बाँटने से T3 बनता है, जिसे किसी coverage report ने नहीं माँगा।
  • जब test environment में किसी statement तक पहुँचना मुमकिन न हो, तो teams उसे साफ़ तौर पर exclude कर सकती हैं, जैसे coverage.py का # pragma: no cover या Istanbul का /* istanbul ignore next */। हर exclusion review करें: excluded code फिर बिल्कुल नहीं नापा जाता।

आज़माएँ: इक्विवैलेंस पार्टीशन जनरेटर आज़माएँ: बाउंड्री वैल्यू जनरेटर

आम गलतियाँ

  • Comments, braces या function signature को statements गिनना, जिससे denominator बदल जाता है।
  • 100% statement coverage को "हर path tested" समझना। इसका मतलब बस इतना है कि हर statement एक बार चला, शायद harmless data के साथ और हर decision के हमेशा एक ही outcome के साथ।
  • सिर्फ़ किसी uncovered statement को चलाने के लिए test लिखना, बिना assertion के या code से copy किए गए expected result के साथ।
  • किसी statement को दो बार गिनना क्योंकि दो tests ने उसे चलाया या loop ने उसे दोहराया: numerator अलग-अलग statements गिनता है।
  • मुश्किल से पहुँचने वाले code को बिना review के exclude करना, जिससे percentage बढ़ता है और risk वहीं रहता है।

QA का नज़रिया

काम पर tester statement coverage शायद ही कभी हाथ से निकालता है; यह tool करता है। लेकिन कुछ बार इसे हाथ से निकालना सिखाता है कि number का मतलब क्या है, ताकि आप reports को critically पढ़ सकें: कौन-से statements कभी नहीं चले, उन्हें कौन-सा decision guard करता है, और क्या कोई requirement उन्हें describe करती है। जब कोई developer "100% statement coverage" report करे, तो पूछें: यह number किन tests से आया, वे क्या assert करते हैं, और किन decision outcomes और data cases तक वे कभी नहीं पहुँचे?

Team में तय करें कि coverage target कौन-सा criterion इस्तेमाल करता है और किस code पर लागू होता है, इसे test plan या CI pipeline के quality gate में लिखें, और scope के साथ report करें: "unit tests, fee module की statement coverage: 100%; free-period check के false outcome का कोई test नहीं"। Risky logic के लिए branch coverage भी माँगें।

अभ्यास

Rating function की statement coverage नापें

आपका काम

Requirement: "Product page customers की average rating एक decimal place के साथ दिखाता है। जिन products का average 4.5 या ज़्यादा है, वे इसकी जगह Top rated दिखाते हैं। जिन products की कोई rating नहीं, वे No ratings yet दिखाते हैं।" नीचे function और उसका इकलौता unit test है; toFixed(1) किसी number को एक decimal place वाले text में बदलता है।

Executable statements गिनें, T1 की statement coverage निकालें, एक test जोड़ें जिससे set 100% तक पहुँचे, और देखें कि requirement का क्या हिस्सा फिर भी untested रह जाता है।

सामग्री
 1  function averageRating(ratings) {
 2    let sum = 0;
 3    for (const r of ratings) {
 4      sum = sum + r;
 5    }
 6    const avg = sum / ratings.length;
 7    if (avg >= 4.5) {
 8      return 'Top rated';
 9    }
10    return avg.toFixed(1);
11  }

Unit test                   Expected      Actual        Result
T1  averageRating([5, 4])   'Top rated'   'Top rated'   passed
चरण
  1. Executable statements को line number से लिखें।
  2. T1 जो statements चलाता है उन्हें चिह्नित करें और उसकी coverage निकालें।
  3. एक test जोड़ें जिससे T1 और नया test मिलकर 100% तक पहुँचें, requirement से लिए गए expected result के साथ।
  4. Requirement का वह वाक्य खोजें जिसे कोई test cover नहीं करता, उसे code में trace करें और तय करें कि वह pass होगा या नहीं।
मॉडल उत्तर दिखाएँ
मॉडल उत्तर

Executable statements: lines 2, 3, 4, 6, 7, 8 और 10, कुल सात।

T1 (sum 9, average 4.5) line 8 से लौटता है। यह lines 2, 3, 4, 6, 7 और 8 चलाता है, line 10 नहीं: 6 / 7 = 86%।

T2 averageRating([3, 4]) जोड़ें: average 3.5, expected 3.5। यह line 10 चलाता है, इसलिए T1 और T2 मिलकर 7 / 7 = 100% तक पहुँचते हैं। कोई अकेला test यह नहीं कर सकता: lines 8 और 10 एक-दूसरे के विकल्प वाले return statements हैं।

"जिन products की कोई rating नहीं, वे No ratings yet दिखाते हैं" को कोई test cover नहीं करता। averageRating([]) trace करें: loop body शून्य बार चलती है, sum / ratings.length यानी 0 / 0, जो JavaScript में NaN (Not a Number) है, NaN >= 4.5 false है, और line 10 string 'NaN' लौटाती है। Expected No ratings yet, actual 'NaN': test fail होता है। Rule कभी implement नहीं हुआ, और line 6, जिसे दोनों tests ने cover किया, सिर्फ़ इसी data पर ग़लत नतीजा देती है।

यानी 100% statement coverage पर भी खाली list (loop में शून्य बार), शून्य से भाग और एक missing requirement, सब untested थे। Product owner के लिए एक सवाल भी है: 4.46 का average 4.5 दिखता है पर badge नहीं मिलता। Rule कौन-सी value इस्तेमाल करे?

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

Statement coverage का अच्छा percentage कितना है?

कोई universal number नहीं है, और ISTQB syllabus कोई number तय नहीं करता। Teams risk के हिसाब से threshold तय करती हैं और उसे अहम code पर, अक्सर changed code पर, लागू करती हैं। Critical statements uncovered रहते हुए ऊँचा total उस कम total से बुरा है जिसमें uncovered code पता है और स्वीकार किया गया है।

100% statement coverage के लिए कितने tests चाहिए?

उतने जितने हर statement तक कम से कम एक बार पहुँचने के लिए लगें, जो अक्सर requirement की ज़रूरत से बहुत कम होते हैं: worked example में एक test, T2, काफ़ी था। Tests की संख्या नतीजा है, लक्ष्य नहीं। पहले requirement से tests design करें, फिर coverage से वह ढूँढें जो उनसे छूट गया।

क्या 100% branch coverage से 100% statement coverage मिलता है?

हाँ। ISTQB syllabus कहता है कि 100% branch coverage से 100% statement coverage हासिल होता है, पर उल्टा नहीं: parking example minutes > 30 का false outcome कभी लिए बिना 100% statement coverage तक पहुँच जाता है। अगला lesson इसकी वजह समझाता है।

संदर्भ

  • ISTQB Certified Tester Foundation Level (CTFL) v4.0ISTQB · 2023सॉफ़्टवेयर टेस्टिंग का फ़ाउंडेशन पाठ्यक्रम: टेस्ट स्तर और प्रकार, टेस्ट डिज़ाइन तकनीकें, टेस्ट प्रबंधन और टूल।
  • 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 से अधिक गहन।

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

क्रमांकित आवश्यकताओं की सूची को requirement-to-test मैट्रिक्स के साथ ट्रेस करने योग्य टेस्ट केस में बदलें।

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

और गहराई से

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

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