Per paskutines dvi savaites teko rašyti ypatingai daug modulių testų (angl. unit tests) ir net pavyko pasiekti „išsvajotą“ 100% kodo aprėptį (angl. code coverage). Iš to gimė mintis parašyti kelių straipsnių ciklą apie rekomendacijas rašant modulių testus.

Modulių testų rekomendacijos – įrankiai ir aplinkos paruošimas
Modulių testų rekomendacijos – 13 modulių testų rašymo taisyklių
Modulių testų rekomendacijos – modulių testas ar integracijų testas?
Modulių testų rekomendacijos – kodo aprėptis

Praeitoje dalyje aš paaiškinau skirtumus tarp modulių testų ir integracijų testų bei išnagrinėjome integracijų testų rašymo taisykles. Šioje, paskutinėje, dalyje mes aptarsime svarbią testavimo metriką – kodo aprėptį.

Kas yra kodo aprėptis?

Kodo aprėptis nusako koks funkcionalumo procentas yra padengtas testais arba kitaip tariant, kokia kodo dalis yra vykdoma leidžiant testus. Natūraliai atrodo, kuo didesnis šis procentas, tuo labiau galima pasitikėti testais. Deja, praktikoje tai ne visada tiesa. Išnagrinėkime klasę StringHelper ir jos testą:

public static class StringHelper
{
  public static string Reverse(string input)
  {
    var arr = input.ToCharArray();
    Array.Reverse(arr);
    return new String(arr);
  }
}

[Test]
public void Given_Not_Empty_String_It_Is_Correctly_Reversed()
{
  // Arrange
  var text = "Test text";
  var reversedText = "txet tseT";

  // Act  
  var result = StringHelper.Reverse(text);

  // Assert
  Assert.AreEqual(reversedText, result);
}

Pateikto testo pilnai užtenka, kad pasiekti 100% StringHelper kodo aprėptį. 100%! Ar tai reiškia, kad mūsų kodas yra visiškai be klaidų? Nebūtinai! Nors testo metu techniškai ir vykdomas visas Reverse metodo kodas, mes nežinome kas įvyks, kai bus perduota null reikšmė. Ogi gausime NullReferenceException pačioje pirmoje Reverse eilutėje. Padarykime tokį tikrinimą:

public static class StringHelper
{
  public static string Reverse(string input)
  {
    if (input == null) throw ArgumentNullException("input");
    var arr = input.ToCharArray();
    Array.Reverse(arr);
    return new String(arr);
  }
}

Toks kodas yra teisingesnis, bet mes jau nebeturime 100% kodo aprėpties. Tam reikia antro testo:

[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void Given_Null_Argument_Exception_Is_Thrown()
{
  // Arrange
  var nullArgument = null;

  // Act
  StringHelper.Reverse(nullArgument);
}

Ir vėl turime 100% aprėptį, ar dabar kodas neturi klaidų? Šį kartą nežinome, ar kodas gerai veiks tu tuščia eilute. Po kelių tokių iteracijų, aš pradėjau suprasti tikrąją testais grindžiamo programavimo (angl. Test Driven Development) naudą, bet čia visai kita tema…

Koks yra rekomenduojamas kodo aprėpties procentas?

Kaip visada, atsakymas į tokius klausimas yra – „priklauso“. Kuo daugiau jūsų metodas turi apsaugų nuo blogų reikšmių, tuo daugiau testų reikia pasiekti gerą kodo aprėptį. Aš prisilaikau tokios nykščio taisyklės – ne mažiau kaip 80%.

 

Štai tiek aš norėjau papasakoti apie savo patirtį dirbant su modulių bei integracijų testais. Kai pradedi rimtai rašyti testus, paaiškėja, kad tai yra kitoks programavimas, reikalaujantis naujų žinių ir kiek kitokio mąstymo.

Patiko (1)

Rodyk draugams