कोड कवरेज के चार सामान्य टाइप

कोड कवरेज के बारे में जानें और उसे मेज़र करने के चार सामान्य तरीके जानें.

क्या आपने "कोड कवरेज" वाक्यांश सुना है? इस पोस्ट में, हम टेस्ट में कोड कवरेज के बारे में जानेंगे. साथ ही, इसे मेज़र करने के चार सामान्य तरीकों के बारे में भी जानेंगे.

कोड कवरेज एक मेट्रिक है, जो आपके टेस्ट के ज़रिए चलाए गए सोर्स कोड का प्रतिशत मेज़र करती है. इससे, उन जगहों का पता लगाने में मदद मिलती है जिनकी ठीक से जांच नहीं की जा सकती.

आम तौर पर, इन मेट्रिक को रिकॉर्ड करने का तरीका ऐसा दिखता है:

फ़ाइल % स्टेटमेंट % 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 {};
}

शाखा कवरेज, कोड में एक्ज़ीक्यूट की गई शाखाओं या फ़ैसले लेने की जगहों के प्रतिशत को मेज़र करता है. जैसे, अगर स्टेटमेंट या लूप. इससे यह तय होता है कि टेस्ट, शर्तों वाले स्टेटमेंट की सही और गलत, दोनों शाखाओं की जांच करते हैं या नहीं.

कोड के उदाहरण में पांच शाखाएं हैं:

  1. सिर्फ़ coffeeName सही का निशान. का इस्तेमाल करके calcCoffeeIngredient को कॉल करना
  2. coffeeName और cup चेक का निशान. की मदद से calcCoffeeIngredient को कॉल किया जा रहा है
  3. कॉफ़ी एस्प्रेसो सही का निशान. है
  4. कॉफ़ी अमेरिकानो X का निशान. है
  5. अन्य कॉफी सही का निशान.

ये टेस्ट, 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 टेस्ट के लिए कोड कवरेज को मेज़र करना मुश्किल और चुनौती भरा होता है. कोड कवरेज का इस्तेमाल करने के बजाय, ज़रूरी शर्तों को कवर करना बेहतर तरीका हो सकता है. इसकी वजह यह है कि E2E टेस्ट का मकसद, आपके टेस्ट की ज़रूरी शर्तों को कवर करना है, न कि सोर्स कोड पर फ़ोकस करना.

नतीजा

कोड कवरेज, आपके टेस्ट के असर को मेज़र करने के लिए एक मददगार मेट्रिक हो सकती है. इससे आपको यह पक्का करने में मदद मिल सकती है कि आपके कोड के ज़रूरी लॉजिक को अच्छी तरह से टेस्ट किया गया है. इससे, ऐप्लिकेशन की क्वालिटी को बेहतर बनाया जा सकता है.

हालांकि, ध्यान रखें कि कोड कवरेज सिर्फ़ एक मेट्रिक है. पक्का करें कि आपको कुछ अन्य बातों को भी ध्यान में रखना चाहिए. जैसे, आपकी जांच की क्वालिटी और आवेदन करने से जुड़ी ज़रूरी शर्तें.

हमारा लक्ष्य, कोड कवरेज को 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({});
  });
});