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ų

Praeitoje dalyje mes išnagrinėjome pagrindinius įrankius, skirtus modulių testavimui bei aptarėme aplinkos paruošimą. Šiame straipsnyje pateiksiu 13 modulių testų rašymo taisyklių, kurių pats prisilaikau jau keletą metų.

ATNAUJINTA

Atsižvelgiant į skaitytojų siūlymus (tiek tinklaraščio komentaruose, tiek Facebook), atnaujinau modulių testų rašymo taisykles.

13 modulių testų rašymo taisyklių

  1. Modulių testų rašymas tai irgi yra programavimas, todėl taikytinos visos standartinės kodo rašymo rekomendacijos
  2. Svarbiausias dalykas kuris turi būti ištestuotas – verslo logika
  3. Reikia turėti pakankamai modulių testų: nei per mažai, nei per daug
  4. Kiekvienas modulių testas turi tikrinti vieną ir tik vieną funkcionalumą
  5. Pagal galimybes reikia izoliuoti testuojamą logiką nuo išorinių resursų (naudojant netikrus objektus ir elgsenos aprašymą (angl. mocking), jeigu nepavyksta to padaryti, dažniausiai tai reiškia dizaino problemą kode ar statinių klasių panaudojimą
  6. Modulių testų vykdymas turi būti greitas
  7. Testų rezultatai tūri būti stabilūs ir determinuoti, tai yra visą laiką grąžinti tą patį rezultatą
  8. Modulių testų rašymo metu naudokite bazinę klasę bei pagalbinius metodus, bet jokių būdų nekvieskite tiesiogiai kitų testų
  9. Jeigu vienos klasės testai turi tą pačią sukūrimo / išvalymo logiką, naudokite specialiai tam skirtas konstrukcijas (Init, SetUp ir panašiai, priklausomai nuo pasirinkto modulių testų karkaso)
  10. Testuokite tik viešas (angl. public) ir vidinio naudojimo (angl. internal) klases, jeigu atsiranda poreikis testuoti privačius metodus (angl. private), dažniausiai tai reiškia šį funkcionalumą reikia iškelti į atskirą klasę
  11. Testo pradžioje apibrėžkite visus parametrus kaip kintamuosius, suteikiant jiems prasmingus pavadinimus
  12. Geriausias būdas dirbti su resursais – naudoti struktūrą try-finaly Kaip teisingai buvo pastebėta kelių skaitytojų – tai labiau liečia integracijų testus, todėl nusprendžiau išimti iš sąrašo
  13. Visi testai turi tenkinti [Arrange]-Act-Assert stilių, kur Arrange dalis nėra privaloma
  14. Testų pavadinimai turėtų pilnai nusakyti sąlygas, testuojamą objektą bei laukiamą rezultatą, pavyzdžiui galima naudoti tokį modulių testų vardų sudarymo šabloną: [Condition][Object][ExpectedResult][Action/Method]

Tikriausiai sutiksite, didžioji dalis aukščiau išvardintų taisyklių yra tiek logiškos, tiek savaime suprantamos. Paskutines 3 taisykles paaiškinsiu dviem pavyzdžiais:

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);
}
public void Given_Not_Existing_Directory_Path_Writer_Sucessfully_Creates_Directory_On_Write()
{
  // Arrange
  var exists = true;
  var doesNotExist = false;
  var dirPath = Path.GetTempPath();
  var text = "Test text";
  var fileSystem = new Mock<IFileSystem>();
  var writer = new FileWriter(fileSystem.Object);

  fileSystem.Setup(fs => fs.CreateDirectoryIfNotExists(It.IsAny<string>())

  // Act
  writer.Write(dirPath, text);

  // Assert
  fileSystem.Verify(fs => fs.CreateDirectoryIfNotExists(dirPath), Times.Once());
}

Arrange dalyje apibrėžiame visus reikalingus objektus ir parametrus bei esant poreikiui aprašome netikrus objektus ir reikalingą jų elgseną. Act dalyje iškviečiame testuojamą metodą su norimais parametrais. Assert dalyje patikriname vieną iš dviejų: arba paprastą Assert sąlygą, arba netikro objekto elgseną. Galiausiai, atkreipkite dėmesį į metodo pavadinimus – vien juos perskaičius galima tiksliai pasakyti kas daroma, esant kokioms pradinėms sąlygoms ir kokio rezultato tikimės.

Iš patirties galiu pasakyti, kad šios taisyklės ženkliai padeda programuotojams be didelės modulių testavimo patirties žengti pirmus žingsnius. Kitoje dalyje aptarsime ideologinius skirtumus tarp modulių testų ir integracijų testų.

Patiko (4)

Rodyk draugams