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

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

"Kod kapsamı" ifadesini duydunuz mu? Bu yayında, testlerdeki kod kapsamının ne olduğunu ve bu kapsamı ölçmek için kullanılan dört yaygın yöntemi inceleyeceğiz.

Kod kapsamı nedir?

Kod kapsamı, testlerinizin yürüttüğü kaynak kodun yüzdesini ölçen bir metriktir. Doğru test yapılmayan alanları belirlemenize yardımcı olur.

Bu metrikler genellikle şu şekilde kaydedilir:

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

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

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

Kod kapsamını toplamak ve hesaplamak için yaygın olarak kullanılan dört yöntem vardır: fonksiyon, 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 bileşenlerini hesaplamak üzere aşağıdaki kod örneğini inceleyin:

/* 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şlev 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ının çalıştırılmaması, kodun bir bölümünün test edilmediği anlamına gelir.

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

Yürütülebilir olmadıklarından function isValidCoffee(name) ve let espresso, water; gibi beyan beyanlarının satır kapsamında değerlendirilmediğini 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ı, koddaki yürütülen dalların veya karar noktalarının (örneğin, if ifadeleri 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. calcCoffeeIngredient adlı kişiye yalnızca coffeeName Onay işareti. ile sesli arama yapılıyor
  2. coffeeName ve cup Onay işareti. ile 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.

Ekstre 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);
}

Bildirim kapsamı, kodunuzdaki testlerinizin yürüttüğü ifadelerin yüzdesini ölçer. İlk bakışta şunu merak edebilirsiniz: "Bu, hat kapsamıyla aynı değil mi?" Aslında, ifade kapsamı satır kapsamına benzer, ancak birden çok ifade içeren tek kod satırlarını hesaba katar.

Kod örneğinde sekiz satırlık çalıştırılabilir kod varken dokuz ifade vardır. İki ifade içeren satırı fark edebiliyor musunuz?

Yanıtınızı kontrol edin

Şu satı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 ekstrenizin kapsamına benzer olur.

Ne tür bir kod kapsamı seçmeniz gerekir?

Çoğu kod kapsam aracı, bu 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ğu için iyi bir başlangıç noktasıdır. Ekstre kapsamının aksine dal kapsamı ve işlev kapsamı, testlerin bir koşul mu (şube) yoksa işlev mi çağırdığını ölçer. Bu nedenle, açıklamadan sonra doğal bir ilerlemedir.

Yüksek beyan kapsamı elde ettikten sonra şube kapsamı ve işlev kapsamına geçebilirsiniz.

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

Hayır. Test kapsamı ve kod kapsamı genellikle birbirine karıştırılır ancak bu iki kavram birbirinden farklıdır:

  • Test kapsamı: Test paketinin, yazılımın özelliklerini ne kadar iyi kapsadığını ölçen niteliksel metriktir. İlgili risk seviyesini belirlemeye yardımcı olur.
  • Kod kapsamı: Test sırasında yürütülen kodun oranını ölçen nicel bir metrik. Asıl önemli olan, testlerin ne kadar kodu kapsadığıdır.

İşte size basitleştirilmiş bir benzetme: Web uygulamasını bir ev olarak düşünün.

  • Test kapsamı, testlerin evdeki odaları ne ölçüde kapsadığını ölçer.
  • Kod kapsamı, testlerin evin ne kadarını incelediğini ölçer.

%100 kod kapsamı, hata olmadığı anlamına gelmez

Test sırasında kod kapsamının yüksek olması kesinlikle istense de% 100 kod kapsamı, kodunuzda hata veya kusur bulunmayacağını garanti etmez.

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

Aşağıdaki testi göz önünde bulundurun:

/* 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, satır, dal ve ifade kapsamı sağlar, ancak kodu gerçekten test etmediği için bu test anlamlı değildir. expect(true).toBe(true) onayı, kodun doğru çalışıp çalışmadığından bağımsız olarak her zaman başarılı olur.

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

Kötü bir metrik, yanlış bir güvenlik algısına neden olabilir. Bu da hiç metrik olmamasından daha kötüdür. Örneğin, %100 kod kapsamına ulaşan bir test paketiniz varsa ancak testlerin hiçbir anlamı yoksa, kodunuzun iyi test edildiğine dair yanlış bir güvenlik algısı elde edebilirsiniz. Uygulama kodunun bir kısmını yanlışlıkla siler veya bozarsanız uygulama artık doğru şekilde çalışmasa bile testler yine de geçer.

Bu senaryoyu önlemek için:

  • Test incelemesi. Anlamlı olduklarından emin olmak için testleri yazıp inceleyin ve kodu çeşitli farklı senaryolarda test edin.
  • Testin etki düzeyinin veya kod kalitesinin tek ölçüsü olarak değil, kod kapsamını kılavuz olarak kullanın.

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

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

  • Ünite testleri. Bunlar, birden fazla küçük senaryoyu ve test yolunu kapsayacak şekilde tasarlandığından kod kapsamını toplamak için en iyi test türüdür.
  • Entegrasyon testleri. Entegrasyon testleri için kod kapsamını toplamaya yardımcı olabilirler ancak bunları dikkatli bir şekilde kullanırlar. Bu durumda, kaynak kodun daha büyük bir bölümünün kapsamını hesaplarsınız ve hangi testlerin aslında kodun hangi bölümlerini kapsadığını belirlemek zor olabilir. Bununla birlikte, entegrasyon testlerinin kod kapsamını hesaplamak, iyi şekilde yalıtılmış birimleri olmayan eski sistemler için yararlı olabilir.
  • Uçtan uca (E2E) testler. Bu testlerin karmaşık yapısı nedeniyle, E2E testlerinde kod kapsamını ölçmek zor ve zordur. E2E testlerinin amacı, kaynak koda odaklanmak yerine testinizin gerekliliklerini karşılamaktır.

Sonuç

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

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

Hedef, %100 kod kapsamını hedeflemek değildir. Bunun yerine, kod kapsamını birim testleri, entegrasyon testleri, uçtan uca testler ve manuel testler gibi çeşitli test yöntemlerini içeren çok kapsamlı bir test planıyla birlikte kullanmalısınız.

Tam kod örneğini ve iyi kod kapsamına sahip testleri inceleyin. Bu canlı demoyla kodu ve testleri de ç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({});
  });
});
{/19.