जानें कि कोड कवरेज क्या है और इसे मेज़र करने के चार सामान्य तरीके क्या हैं.
क्या आपने "कोड कवरेज" वाक्यांश सुना है? इस पोस्ट में, हम टेस्ट में कोड कवरेज के बारे में जानेंगे. साथ ही, इसे मेज़र करने के चार सामान्य तरीकों के बारे में भी जानेंगे.
कोड कवरेज क्या है?
कोड कवरेज एक मेट्रिक है, जो आपके टेस्ट के ज़रिए चलाए गए सोर्स कोड का प्रतिशत मेज़र करती है. इससे आपको उन जगहों की पहचान करने में मदद मिलती है जहां शायद सही तरीके से जांच न की गई हो.
आम तौर पर, इन मेट्रिक को रिकॉर्ड करने का तरीका ऐसा दिखता है:
फ़ाइल | % स्टेटमेंट | % Branch | % फ़ंक्शन | % लाइनें | कवर नहीं की गई लाइनें |
---|---|---|---|---|---|
file.js | 90% | 100% | 90% | 80% | 89,256 |
coffee.js | 55.55% | 80% | 50% | 62.5% | 10-11, 18 |
नई सुविधाएं और टेस्ट जोड़ने पर, कोड कवरेज के प्रतिशत में बढ़ोतरी होने से आपको यह भरोसा मिलता है कि आपके ऐप्लिकेशन की पूरी तरह से जांच की जा चुकी है. हालांकि, इसके अलावा और भी बहुत कुछ है.
कोड कवरेज के चार सामान्य टाइप
कोड कवरेज को इकट्ठा करने और उसका हिसाब लगाने के चार सामान्य तरीके हैं: फ़ंक्शन, लाइन, शाखा, और स्टेटमेंट कवरेज.
हर तरह के कोड कवरेज का प्रतिशत कैसे कैलकुलेट होता है, यह जानने के लिए कॉफी के कॉम्पोनेंट का हिसाब लगाने के लिए, यहां दिया गया कोड उदाहरण देखें:
/* coffee.js */
export function calcCoffeeIngredient(coffeeName, cup = 1) {
let espresso, water;
if (coffeeName === 'espresso') {
espresso = 30 * cup;
return { espresso };
}
if (coffeeName === 'americano') {
espresso = 30 * cup; water = 70 * cup;
return { espresso, water };
}
return {};
}
export function isValidCoffee(name) {
return ['espresso', 'americano', 'mocha'].includes(name);
}
calcCoffeeIngredient
फ़ंक्शन की पुष्टि करने वाले टेस्ट ये हैं:
/* coffee.test.js */
import { describe, expect, assert, it } from 'vitest';
import { calcCoffeeIngredient } from '../src/coffee-incomplete';
describe('Coffee', () => {
it('should have espresso', () => {
const result = calcCoffeeIngredient('espresso', 2);
expect(result).to.deep.equal({ espresso: 60 });
});
it('should have nothing', () => {
const result = calcCoffeeIngredient('unknown');
expect(result).to.deep.equal({});
});
});
इस लाइव डेमो पर कोड और टेस्ट चलाए जा सकते हैं या रिपॉज़िटरी देखी जा सकती है.
फ़ंक्शन कवरेज
कोड कवरेज: 50%
/* coffee.js */
export function calcCoffeeIngredient(coffeeName, cup = 1) {
// ...
}
function isValidCoffee(name) {
// ...
}
फ़ंक्शन कवरेज एक आसान मेट्रिक है. यह आपके कोड में मौजूद उन फ़ंक्शन का प्रतिशत कैप्चर करता है जिन्हें आपकी जांचें कॉल करती हैं.
कोड के उदाहरण में, दो फ़ंक्शन हैं: calcCoffeeIngredient
और isValidCoffee
. टेस्ट में सिर्फ़ calcCoffeeIngredient
फ़ंक्शन को कॉल किया जाता है, इसलिए फ़ंक्शन कवरेज 50% है.
लाइन कवरेज
कोड कवरेज: 62.5%
/* coffee.js */
export function calcCoffeeIngredient(coffeeName, cup = 1) {
let espresso, water;
if (coffeeName === 'espresso') {
espresso = 30 * cup;
return { espresso };
}
if (coffeeName === 'americano') {
espresso = 30 * cup; water = 70 * cup;
return { espresso, water };
}
return {};
}
export function isValidCoffee(name) {
return ['espresso', 'americano', 'mocha'].includes(name);
}
लाइन कवरेज, उन कोड लाइनों का प्रतिशत मेज़र करता है जिन्हें आपके टेस्ट सुइट ने चलाया है. अगर कोड की कोई लाइन लागू नहीं होती है, तो इसका मतलब है कि कोड के किसी हिस्से की जांच नहीं की गई है.
कोड के उदाहरण में, लाल और हरे रंग में हाइलाइट किए गए आठ लाइन वाले कोड को चलाया जा सकता है. हालांकि, टेस्ट में americano
शर्त (दो लाइन) और isValidCoffee
फ़ंक्शन (एक लाइन) को नहीं चलाया जाता. इससे लाइन कवरेज 62.5% हो जाती है.
ध्यान दें कि लाइन कवरेज में, function isValidCoffee(name)
और let espresso, water;
जैसे एलान वाले स्टेटमेंट शामिल नहीं किए जाते, क्योंकि उन्हें लागू नहीं किया जा सकता.
शाखा की कवरेज
कोड कवरेज: 80%
/* coffee.js */
export function calcCoffeeIngredient(coffeeName, cup = 1) {
// ...
if (coffeeName === 'espresso') {
// ...
return { espresso };
}
if (coffeeName === 'americano') {
// ...
return { espresso, water };
}
return {};
}
…
शाखा कवरेज, कोड में एक्ज़ीक्यूट की गई शाखाओं या फ़ैसले लेने की जगहों के प्रतिशत को मेज़र करता है. जैसे, अगर स्टेटमेंट या लूप. इससे यह तय होता है कि टेस्ट, शर्तों वाले स्टेटमेंट की सही और गलत शाखाओं, दोनों की जांच करते हैं या नहीं.
कोड के उदाहरण में पांच शाखाएं हैं:
- सिर्फ़
coffeeName
का इस्तेमाल करकेcalcCoffeeIngredient
को कॉल करना coffeeName
औरcup
की मदद सेcalcCoffeeIngredient
को कॉल किया जा रहा है- कॉफ़ी एस्प्रेसो है
- कॉफ़ी, अमेरिकानो है
- अन्य कॉफी
ये टेस्ट, Coffee is Americano
शर्त को छोड़कर सभी शाखाओं को कवर करते हैं. इसलिए, शाखा कवरेज 80% है.
स्टेटमेंट कवरेज
कोड कवरेज: 55.55%
/* coffee.js */
export function calcCoffeeIngredient(coffeeName, cup = 1) {
let espresso, water;
if (coffeeName === 'espresso') {
espresso = 30 * cup;
return { espresso };
}
if (coffeeName === 'americano') {
espresso = 30 * cup; water = 70 * cup;
return { espresso, water };
}
return {};
}
export function isValidCoffee(name) {
return ['espresso', 'americano', 'mocha'].includes(name);
}
स्टेटमेंट कवरेज से पता चलता है कि आपके कोड में मौजूद किन स्टेटमेंट की जांच की गई. पहली नज़र में, आपको लग सकता है कि “क्या यह लाइन कवरेज जैसी ही है?” असल में, स्टेटमेंट कवरेज, लाइन कवरेज जैसी ही होती है. हालांकि, इसमें कोड की एक ऐसी लाइन को ध्यान में रखा जाता है जिसमें कई स्टेटमेंट होते हैं.
कोड के उदाहरण में, आठ लाइनें ऐसी हैं जिनमें कोड को चलाया जा सकता है, लेकिन नौ स्टेटमेंट हैं. क्या आपको वह लाइन दिख रही है जिसमें दो स्टेटमेंट हैं?
espresso = 30 * cup; water = 70 * cup;
इन टेस्ट में नौ में से सिर्फ़ पांच स्टेटमेंट शामिल हैं. इसलिए, स्टेटमेंट कवरेज 55.55% है.
अगर हर लाइन में एक स्टेटमेंट लिखा जाता है, तो आपकी लाइन कवरेज, स्टेटमेंट कवरेज जैसी ही होगी.
आपको किस तरह की कोड कवरेज चुननी चाहिए?
ज़्यादातर कोड कवरेज टूल में, ये चार तरह की सामान्य कोड कवरेज शामिल होती हैं. यह चुनना कि कोड कवरेज की किस मेट्रिक को प्राथमिकता दी जाए, यह प्रोजेक्ट की ज़रूरी शर्तों, डेवलपमेंट के तरीकों, और टेस्टिंग के लक्ष्यों पर निर्भर करता है.
आम तौर पर, स्टेटमेंट कवरेज से शुरुआत करना एक अच्छा तरीका है, क्योंकि यह एक आसान और समझने में आसान मेट्रिक है. स्टेटमेंट कवरेज के उलट, शाखा कवरेज और फ़ंक्शन कवरेज से यह पता चलता है कि टेस्ट किसी शर्त (शाखा) या फ़ंक्शन को कॉल करते हैं या नहीं. इसलिए, ये स्टेटमेंट कवरेज के बाद, स्वाभाविक तौर पर दिखते हैं.
स्टेटमेंट कवरेज की ज़्यादा दर हासिल करने के बाद, ब्रांच कवरेज और फ़ंक्शन कवरेज पर आगे बढ़ें.
क्या टेस्ट कवरेज और कोड कवरेज एक ही है?
नहीं. टेस्ट कवरेज और कोड कवरेज को अक्सर एक ही समझा जाता है, लेकिन ये अलग-अलग होते हैं:
- टेस्ट कवरेज: यह एक क्वालिटी मेट्रिक है, जो यह मेज़र करती है कि टेस्ट सुइट, सॉफ़्टवेयर की सुविधाओं को कितनी अच्छी तरह कवर करता है. इससे, खतरे के लेवल का पता लगाने में मदद मिलती है.
- कोड कवरेज: यह एक संख्यात्मक मेट्रिक है, जो जांच के दौरान चलाए गए कोड के अनुपात को मेज़र करती है. यह इस बात पर निर्भर करता है कि टेस्ट कितने कोड को कवर करते हैं.
यहां एक आसान उदाहरण दिया गया है: किसी वेब ऐप्लिकेशन को घर के तौर पर कल्पना करें.
- टेस्ट कवरेज से पता चलता है कि टेस्ट, घर के कमरों को कितनी अच्छी तरह कवर करते हैं.
- कोड कवरेज से पता चलता है कि टेस्ट में घर के कितने हिस्से की जांच की गई है.
100% कोड कवरेज का मतलब यह नहीं है कि कोई गड़बड़ी नहीं है
टेस्टिंग में ज़्यादा कोड कवरेज हासिल करना ज़रूरी है. हालांकि, 100% कोड कवरेज होने का मतलब यह नहीं है कि आपके कोड में कोई गड़बड़ी या खामी नहीं है.
कोड कवरेज को 100% करने का बेमतलब तरीका
इस टेस्ट पर ध्यान दें:
/* coffee.test.js */
// ...
describe('Warning: Do not do this', () => {
it('is meaningless', () => {
calcCoffeeIngredient('espresso', 2);
calcCoffeeIngredient('americano');
calcCoffeeIngredient('unknown');
isValidCoffee('mocha');
expect(true).toBe(true); // not meaningful assertion
});
});
इस टेस्ट से फ़ंक्शन, लाइन, शाखा, और स्टेटमेंट कवरेज 100% हो जाता है. हालांकि, इसका कोई मतलब नहीं है, क्योंकि यह असल में कोड की जांच नहीं करता. expect(true).toBe(true)
एश्योरेशन हमेशा पास होगा, भले ही कोड सही तरीके से काम करता हो या नहीं.
कोई मेट्रिक न होने से बेहतर है कि आपके पास खराब मेट्रिक हो
खराब मेट्रिक से आपको सुरक्षा का गलत भरोसा हो सकता है. यह किसी भी मेट्रिक के न होने से भी ज़्यादा खराब है. उदाहरण के लिए, अगर आपके पास ऐसा टेस्ट सुइट है जो 100% कोड कवरेज हासिल करता है, लेकिन टेस्ट का कोई मतलब नहीं है, तो आपको यह गलतफ़हमी हो सकती है कि आपके कोड की अच्छी तरह से जांच की गई है. अगर गलती से ऐप्लिकेशन कोड का कोई हिस्सा मिट जाता है या खराब हो जाता है, तो भी जांच पास हो जाएगी. भले ही, ऐप्लिकेशन अब सही तरीके से काम न करे.
इस स्थिति से बचने के लिए:
- समीक्षा की जांच करना. जांच लिखें और उनकी समीक्षा करें, ताकि यह पक्का किया जा सके कि वे काम की हैं. साथ ही, अलग-अलग स्थितियों में कोड की जांच करें.
- कोड कवरेज का इस्तेमाल, टेस्ट के असर या कोड की क्वालिटी का आकलन करने के लिए न करें, बल्कि इसे एक दिशा-निर्देश के तौर पर इस्तेमाल करें.
अलग-अलग तरह की टेस्टिंग में कोड कवरेज का इस्तेमाल करना
आइए, तीन तरह के सामान्य टेस्ट के साथ कोड कवरेज का इस्तेमाल करने के तरीके के बारे में ज़्यादा जानें:
- यूनिट टेस्ट. कोड कवरेज इकट्ठा करने के लिए, ये टेस्ट टाइप सबसे अच्छे होते हैं. ऐसा इसलिए, क्योंकि इन्हें कई छोटे-मोटे मामलों और टेस्टिंग पाथ को कवर करने के लिए डिज़ाइन किया गया है.
- इंटिग्रेशन टेस्ट. इनसे इंटिग्रेशन टेस्ट के लिए कोड कवरेज इकट्ठा करने में मदद मिल सकती है. हालांकि, इनका इस्तेमाल सावधानी से करें. इस मामले में, सोर्स कोड के बड़े हिस्से की कवरेज का हिसाब लगाया जाता है. साथ ही, यह तय करना मुश्किल हो सकता है कि कौनसी टेस्ट, कोड के किन हिस्सों को कवर करती हैं. इसके बावजूद, इंटिग्रेशन टेस्ट के कोड कवरेज का हिसाब लगाना, उन लेगसी सिस्टम के लिए फ़ायदेमंद हो सकता है जिनमें अच्छी तरह से अलग-अलग यूनिट नहीं होती हैं.
- शुरू से आखिर तक (E2E) टेस्ट. E2E टेस्ट की जटिल प्रकृति की वजह से, इनके लिए कोड कवरेज को मेज़र करना मुश्किल और चुनौती भरा होता है. कोड कवरेज का इस्तेमाल करने के बजाय, ज़रूरी शर्तों को कवर करना बेहतर तरीका हो सकता है. इसकी वजह यह है कि ई2ई टेस्ट का मकसद, आपके टेस्ट की ज़रूरी शर्तों को कवर करना है, न कि सोर्स कोड पर फ़ोकस करना.
नतीजा
कोड कवरेज, आपके टेस्ट के असर को मेज़र करने के लिए एक मददगार मेट्रिक हो सकती है. इससे आपको अपने ऐप्लिकेशन की क्वालिटी को बेहतर बनाने में मदद मिल सकती है. ऐसा करने के लिए, यह पक्का किया जाता है कि आपके कोड में मौजूद अहम लॉजिक की अच्छी तरह से जांच की गई हो.
हालांकि, ध्यान रखें कि कोड कवरेज सिर्फ़ एक मेट्रिक है. टेस्ट की क्वालिटी और आवेदन की ज़रूरी शर्तों जैसे अन्य फ़ैक्टर भी ध्यान में रखें.
हमारा लक्ष्य, कोड कवरेज को 100% तक पहुंचाना नहीं है. इसके बजाय, आपको कोड कवरेज के साथ-साथ, बेहतर टेस्टिंग प्लान का इस्तेमाल करना चाहिए. इसमें टेस्टिंग के कई तरीके शामिल होते हैं. जैसे, यूनिट टेस्ट, इंटिग्रेशन टेस्ट, एंड-टू-एंड टेस्ट, और मैन्युअल टेस्ट.
कोड का पूरा उदाहरण और अच्छी कोड कवरेज वाले टेस्ट देखें. इस लाइव डेमो की मदद से, कोड और टेस्ट भी चलाए जा सकते हैं.
/* coffee.js - a complete example */
export function calcCoffeeIngredient(coffeeName, cup = 1) {
if (!isValidCoffee(coffeeName)) return {};
let espresso, water;
if (coffeeName === 'espresso') {
espresso = 30 * cup;
return { espresso };
}
if (coffeeName === 'americano') {
espresso = 30 * cup; water = 70 * cup;
return { espresso, water };
}
throw new Error (`${coffeeName} not found`);
}
function isValidCoffee(name) {
return ['espresso', 'americano', 'mocha'].includes(name);
}
/* coffee.test.js - a complete test suite */
import { describe, expect, it } from 'vitest';
import { calcCoffeeIngredient } from '../src/coffee-complete';
describe('Coffee', () => {
it('should have espresso', () => {
const result = calcCoffeeIngredient('espresso', 2);
expect(result).to.deep.equal({ espresso: 60 });
});
it('should have americano', () => {
const result = calcCoffeeIngredient('americano');
expect(result.espresso).to.equal(30);
expect(result.water).to.equal(70);
});
it('should throw error', () => {
const func = () => calcCoffeeIngredient('mocha');
expect(func).toThrowError(new Error('mocha not found'));
});
it('should have nothing', () => {
const result = calcCoffeeIngredient('unknown')
expect(result).to.deep.equal({});
});
});