Yaygın olarak kullanılan dört kod kapsamı türü

Kod kapsamının ne olduğunu ve kapsamı ölçmenin dört yaygın yolunu keşfedin.

"Kod kapsamı" ifadesini duydunuz mu? Bu gönderide, testlerdeki kod kapsamının ne olduğunu ve bunu ölçmenin dört yaygın yöntemini ele alacağız.

Kod kapsamı nedir?

Kod kapsamı, testlerinizin yürüttüğü kaynak kodunun yüzdesini ölçen bir metriktir. Uygun testlerin yapılamayan alanları belirlemenize yardımcı olur.

Çoğunlukla, bu metrikleri kaydetmek şu şekilde görünür:

Dosya % İfadeleri Şube Yüzdesi İşlevlerin yüzdesi Satır Yüzdesi Açık olmayan satırlar
file.js %90 %100 %90 %80 89.256
coffee.js %55,55 %80 %50 %62,5 10-11, 18

Siz yeni özellikler ve testler ekledikçe kod kapsamı yüzdelerini artırmak, uygulamanızın kapsamlı şekilde test edildiğinden emin olmanızı sağlayabilir. Ancak keşfedilecek daha pek çok konu var.

Yaygın olarak kullanılan dört kod kapsamı türü

Kod kapsamını toplamak ve hesaplamak için sık kullanılan dört yöntem vardır: işlev, satır, dal ve ifade kapsamı.

Dört tür metin kapsamı.

Her bir kod kapsamı türünün yüzdesini nasıl hesapladığını görmek için, kahve içeriklerini hesaplamak üzere aşağıdaki kod örneğini göz önünde bulundurun:

/* 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 işlevini doğrulayan testler şunlardır:

/* 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({});
  });
});

Bu canlı demoda kodu ve testleri çalıştırabilir veya depoya göz atabilirsiniz.

İşlev kapsamı

Kod kapsamı: %50

/* coffee.js */

export function calcCoffeeIngredient(coffeeName, cup = 1) {
  // ...
}

function isValidCoffee(name) {
  // ...
}

İşlev kapsamı basit bir metriktir. Kodunuzda testlerinizin çağırdığı işlevlerin yüzdesini yakalar.

Kod örneğinde iki işlev vardır: calcCoffeeIngredient ve isValidCoffee. Testler yalnızca calcCoffeeIngredient işlevini çağırır, bu nedenle işlevin kapsamı %50 olur.

Hat kapsamı

Kod kapsamı: %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);
}

Satır kapsamı, test paketinizin yürüttüğü yürütülebilir kod satırlarının yüzdesini ölçer. Bir kod satırı yürütülmeden kalırsa bu, kodun bir kısmının test edilmemiş olduğu anlamına gelir.

Kod örneğinde sekiz satırlık yürütülebilir kod (kırmızı ve yeşil renkle vurgulanmıştır) ancak testler americano koşulunu (iki satır) ve isValidCoffee işlevini (tek satır) yürütmez. Bu, %62,5'lik bir çizgi kapsamıyla sonuçlanır.

function isValidCoffee(name) ve let espresso, water; gibi beyan ifadeleri yürütülebilir olmadığından satır kapsamının dikkate almadığını unutmayın.

Şube kapsamı

Kod kapsamı: %80

/* coffee.js */

export function calcCoffeeIngredient(coffeeName, cup = 1) {
  // ...

  if (coffeeName === 'espresso') {
    // ...
    return { espresso };
  }

  if (coffeeName === 'americano') {
    // ...
    return { espresso, water };
  }

  return {};
}
…

Şube kapsamı, yürütülen dalların veya koddaki karar noktalarının (ör. ifadeler veya döngüler) yüzdesini ölçer. Testlerin, koşullu ifadelerin hem doğru hem de yanlış dallarını inceleyip incelemediğini belirler.

Kod örneğinde beş dal vardır:

  1. Yalnızca coffeeName Onay işareti. ile calcCoffeeIngredient aranıyor
  2. coffeeName ve cup Onay işareti. üzerinden calcCoffeeIngredient aranıyor
  3. Kahve: Espresso Onay işareti.
  4. Kahve: Americano X işareti.
  5. Diğer kahve Onay işareti.

Testler, Coffee is Americano koşulu hariç tüm dalları kapsar. Yani şube kapsamı %80.

Hesap özeti kapsamı

Kod kapsamı: %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);
}

Ekstre kapsamı, testlerinizin yürüttüğü kodda ifadelerin yüzdesini ölçer. İlk bakışta "Bu, çizgi kapsamının aynısı değil mi?" diye sorabilirsiniz. Gerçekten de ifade kapsamı, satır kapsamına benzer, ancak birden çok ifade içeren tek kod satırını dikkate alır.

Kod örneğinde sekiz satır yürütülebilir kod vardır ancak dokuz ifade bulunur. Satırda iki ifade olduğunu fark edebiliyor musunuz?

Yanıtınızı kontrol etme

Bu satır şu satırdır: espresso = 30 * cup; water = 70 * cup;

Testler dokuz ifadeden yalnızca beşini kapsadığından ifade kapsamı %55, 55'tir.

Her satıra her zaman bir ifade yazarsanız satır kapsamınız, ekstre kapsamınıza benzer olacaktır.

Ne tür bir kod kapsamı seçmelisiniz?

Kod kapsamı araçlarının çoğu, aşağıdaki dört yaygın kod kapsamı türünü içerir. Hangi kod kapsamı metriğine öncelik verileceğini seçmek, belirli proje gereksinimlerine, geliştirme uygulamalarına ve test hedeflerine bağlıdır.

Genel olarak ifade kapsamı, basit ve anlaşılması kolay bir metrik olduğundan iyi bir başlangıç noktasıdır. İfade kapsamının aksine dal kapsamı ve işlev kapsamı, testlerin bir koşulu (dal) mı yoksa işlevi mi çağırdığını ölçer. Bu nedenle, ifadeden sonra doğal bir ilerlemedir.

Geniş bir ifade kapsamı elde ettikten sonra şubelere ve işlev kapsamına devam edebilirsiniz.

Test kapsamı kod kapsamıyla aynı mı?

Hayır. Test kapsamı ve kod kapsamı çoğu zaman karışıktır ancak farklıdır:

  • Test kapsamı: Test paketinin, yazılımın özelliklerini ne kadar iyi kapsadığını ölçen niteliksel metrik. İlgili risk düzeyinin belirlenmesine yardımcı olur.
  • Kod kapsamı: Test sırasında yürütülen kodun oranını ölçen niceliksel bir metrik. Konu, testlerin ne kadar kodu kapsadığıyla ilgilidir.

Basitleştirilmiş bir analoji şöyledir: Bir web uygulamasını bir ev olarak düşünün.

  • Test kapsamı, testlerin evdeki odaları ne kadar iyi kapsadığını ölçer.
  • Kod kapsamı, testlerin evin ne kadarının geçtiğini ölçer.

Kodların% 100 kapsamına alınması, hata meydana gelmediği anlamına gelmez.

Testlerde kod kapsamının yüksek olması istense de% 100 kod kapsamı, kodunuzda hata veya kusur bulunmadığını garanti etmez.

%100 kod kapsamına ulaşmanın anlamsız bir yolu

Aşağıdaki testi değerlendirin:

/* 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
  });
});

Bu test% 100 işlev, çizgi, dal ve ifade kapsamı elde eder, ancak kodu gerçekten test etmediği için hiçbir anlam ifade etmez. expect(true).toBe(true) onayı, kodun doğru çalışıp çalışmadığına bakılmaksızın her zaman başarılı olur.

Kötü bir metrik, hiç metrik olmamasından daha kötüdür

Kötü bir metrik, size yanlış bir güvenlik duygusu verebilir. Bu, hiç metrik olmamasından daha kötüdür. Örneğin, %100 kod kapsamına ulaşan bir test paketiniz varsa ancak testlerin hepsi anlamsızsa kodunuzun başarılı olduğuna dair yanlış bir güvenlik algısı yaşayabilirsiniz. Uygulama kodunun bir bölümünü yanlışlıkla silerseniz veya kırırsanız, uygulama artık doğru şekilde çalışmasa bile testler başarılı olur.

Bu senaryodan kaçınmak için:

  • Test incelemesi. Anlamlı olduklarından emin olmak için testler yazın ve inceleyin. Ardından, kodu çeşitli senaryolarda test edin.
  • Kod kapsamını testin etkinliğini veya kod kalitesini gösteren tek ölçüm olarak değil, yönergeler olarak kullanın.

Farklı test türlerinde kod kapsamını kullanma

Yaygın olarak kullanılan üç test türüyle kod kapsamını nasıl kullanabileceğinize daha yakından bakalım:

  • Birim testleri. Birden çok küçük senaryoyu ve test yolunu kapsayacak şekilde tasarlanmış olduklarından kod kapsamını toplamak için en iyi test türüdür.
  • Entegrasyon testleri. Bunlar, entegrasyon testleri için kod kapsamının toplanmasına yardımcı olabilir ancak dikkatli bir şekilde kullanın. Bu durumda kaynak kodun daha büyük bir kısmının kapsamını hesaplarsınız ve hangi testlerin gerçekten kodun hangi bölümlerini kapsadığını belirlemek zor olabilir. Bununla birlikte, entegrasyon testlerinin kod kapsamını hesaplamak, iyi yalıtılmış birimlere sahip olmayan eski sistemler için yararlı olabilir.
  • Uçtan uca (E2E) testler. E2E testlerinin kod kapsamının ölçülmesi, bu testlerin karmaşık yapısı nedeniyle zor ve zorlu bir işlemdir. Bu durumda, kod kapsamı yerine gereksinim kapsamı daha iyi bir seçenek olabilir. Bunun nedeni, E2E testlerinin kaynak koda odaklanmayı değil, testin gerekliliklerini karşılamaya odaklanmasıdır.

Sonuç

Kod kapsamı, testlerinizin etkinliğini ölçmek için yararlı bir metrik olabilir. Kodunuzdaki kritik mantığın iyi bir şekilde test edilmesini sağlayarak uygulamanızın kalitesini artırmanıza yardımcı olabilir.

Ancak, kod kapsamının tek bir metrik olduğunu unutmayın. Testlerinizin kalitesi ve başvuru şartlarınız gibi diğer faktörleri de göz önünde bulundurun.

%100 kod kapsamını hedeflemek amaçlanmamıştır. Bunun yerine, kod kapsamının yanı sıra birim testleri, entegrasyon testleri, uçtan uca testler ve manuel testler gibi çeşitli test yöntemlerini içeren çok yönlü bir test planı kullanmalısınız.

Kod örneğinin tamamını ve iyi kod kapsamı olan testleri inceleyin. Kodu ve testleri bu canlı demoyla da çalıştırabilirsiniz.

/* 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({});
  });
});