Értem, mindannyian. A tesztelés nem éppen a legszórakoztatóbb dolog, amit a fejlesztés során tehetünk.

De tudod, mi még kevésbé szórakoztató, mint a tesztelés?

Így van, hibakeresés.

Bárcsak lenne mód arra, hogy előre jelezzük a kódunkban előforduló hibákat, mielőtt azok ténylegesen megtörténnének. Ez annyi időt és stresszt takarít meg, amit életünk más részein is felhasználhatunk.

Itt jön be a tesztvezérelt fejlesztés, hogy megmentse a helyzetet. A tesztvezérelt fejlesztés vagy a TDD alapvetően a tesztek írása, mielőtt bármilyen kódot vagy függvényt írna a programba.

A TDD a gyakorlatban tulajdonképpen egy ciklus, ahol először megírjuk a sikertelen teszteket, majd megírjuk a minimális funkcionalitást ahhoz, hogy a teszt sikeres legyen, majd végül a programot úgy alakítjuk át, hogy a külső viselkedés megváltoztatása nélkül javítsuk azt.

Ezt a ciklust általában három szóval jelölik: PIROS, ZÖLD, REFAKTOR.

Beszéljük meg őket egyenként.

PIROS

A piros a TDD három ciklusa közül az első. Pirossal meg kell írnunk az aktuális funkció vagy lemaradás céljának eléréséhez szükséges teszteket.

Hadd hangsúlyozzam, hogy a tesztek akkor és csak akkor sikeresek, ha az aktuális lemaradáshoz szükséges összes felhasználói sztorit teljesítették. Ha a tesztek ezt megelőzően átmennek, akkor még nem értük el a kívánt célt vagy elfogadási kritériumokat az adott tulajdonsághoz.

Tehát hogyan írjunk jó teszteket, amelyek nemcsak a felhasználói történetet teljesítik, hanem tiszták és olvashatók is az Ön és mások számára, akik veled dolgoznak?

Szerencsére Bob Martin¹ Clean Codekönyvéből az F.I.R.S.T elve tesztelhető:

  • Fast: A teszteknek elég gyorsaknak kell lenniük ahhoz, hogy ne tántorítsák el Önt vagy más programozókat a tesztelési eljárás inicializálásától.
  • Ifüggetlen: Minden tesztnek függetlennek kell lennie, nem függhet a korábban megtörtént tesztektől. Ha a tesztekhez adatokra van szükség, akkor ezeket az adatokat a teszt legelején kell beállítani, nem az előzőnél.
  • Imegismételhető: A teszteknek bármilyen környezetben futniuk kell, legyen az a helyi gépen, mások gépein vagy a git tárolóban. Ha a tesztek sikertelenek, az azért van, mert a program működése nem megfelelő, semmi más.
  • Sönellenőrzés: A teszteknek meg kell mondaniuk, hogy sikeres-e vagy sem. Nem követelheti meg a fejlesztőktől, hogy manuálisan ellenőrizzék a teszt kimenetét annak eldöntése érdekében, hogy a teszt sikeres-e vagy sem. Ezt megtehetjük egy logikai érték visszaadásával, vagy a legtöbb programozási nyelvben vagy tesztkeretrendszerben elérhető assert módszer használatával.
  • Timely: A teszteket közvetlenül azelőtt kell megírni, hogy a programozó megírja a kódot, hogy az sikeres legyen, és nem utána. Ez különösen igaz, ha követjük a TDD-t (ami vagyunk!).

A tesztek megírása után, megbizonyosodva arról, hogy az érvényesíti a felhasználói történetünk elfogadási feltételeit, valamint az F.I.R.S.T elvet követve, véglegesíthetjük kódunkat.

A véglegesítési üzenetnek [RED]-vel kell kezdődnie, jelezve, hogy a TDD-ciklusunk piros fázisában vagyunk, és a tesztek meghiúsulnak.

ZÖLD

Miután megírtuk tesztjeinket, és elhelyeztük a tárolónkban, most el kell kezdenünk a kódunk megvalósítását. Ebben a fázisban az a célunk, hogy minden olyan teszt sikeres legyen, amely korábban a piros szakaszon megbukott.

Jelenleg ez az egyetlen célunk, hogy megírjuk a minimális kódot, amely a tesztek sikeres teljesítéséhez és a felhasználói történet teljesítéséhez szükséges.

Ha végzett, véglegesítse a kódot a [ZÖLD] kezdetű véglegesítési üzenettel, jelezve, hogy az elvégzett teszteknek mostanra sikeresnek kell lenniük.

REFAKTOR

Miután megírtuk a kódot, itt a lehetőség az újrafaktorizálásra. Ne feledje, hogy a TDD ciklus Green lépésénél meg kell írnunk a minimális implementációt, hogy átmenjünk a Rednél írt teszteken.

Tehát mit tehetünk ebben a szakaszban? Nos, kezdhetjük azzal, hogy megszabadulunk a fel nem használt változóktól és importálástól, átnevezzük a tisztázatlan változókat és függvényeket, és megtisztítjuk a kódunkat.

De hogyan tisztítsuk meg a kódunkat?

Szerencsére van "itt" egy nagyszerű cikk, amelyet valóban az Ön által írt. Feltétlenül olvassa el ezt, miután elolvasta ezt!

Kód lefedettsége

A kódlefedettség annak mennyiségi mérése, hogy hány sor vagy kódblokk kerül végrehajtásra a tesztek futása közben. Más szavakkal, azt méri, hogy a kódból mennyit teszteltek.

A kódlefedettség mérése percentilis formátumban történik, 0 és 100% között. Ez azt jelenti, hogy ha a kód lefedettsége 85%, akkor a kód 15%-a még nem tesztelt.

A cél mindig a 100%-os elérése legyen, bár a valóság ettől eltérhet. A 100%-os kódlefedettség elérése biztosítja, hogy a kód jól tesztelt és hibamentes legyen.

TDD akcióban

Most, hogy félretettük az elméletet, vessünk egy pillantást a TDD megvalósítására projektünkben.

Itt egy fejlesztő (én!) ír egy tesztet egy új funkcióhoz a TDD ciklus Red szakaszában. A pipeline ekkor (meglepetés, meglepetés) meghiúsul, mert még nincs megírva a tesztek megvalósítása.

Ezután a fejlesztő kódolja a funkció megvalósítását, és a folyamat átmegy. Ennek az az oka, hogy az előző commitban írt tesztek sikeresek voltak, ami azt jelzi, hogy a felhasználói történet teljesítésének célja megvalósult.

Végül ez a fejlesztő úgy alakítja át az alkalmazást, hogy megszabadul a kódtól, amelyet végül nem használtak.

Következtetés

A TDD tökéletes?

No.

Egyes fejlesztők számára a tesztek készítése egyszerűen nem élvezetes. Néha a fejlesztők is küszködnek a tesztelési könyvtárral, és kitalálják, hogy a tesztelési könyvtár melyik kódja milyen funkcionalitást tesztel.

De vajon ez a legjobb gyakorlat?

Egyelőre igen. Különösen, ha meg akarjuk őrizni alkalmazásunk kódjának minőségét. A kódunk tesztelése a funkcionalitás megvalósítása előtt biztosítja, hogy a kód mentes legyen a hibáktól, és megfelel a hátralék elfogadási feltételeinek.

[1]: Tiszta kód, Bob Martin