Végleges útmutató az egység teszteléséhez Jest és React-Testing segítségével React alkalmazásokban

Bevezetés

Fejlesztőként a lista elején lévő egyik dolognak a hibamentes kód szállításának kell lennie. Semmi sem lehet rosszabb, mint csütörtök este megtudni, hogy a hétfőn végrehajtott változtatások feltörték az élő alkalmazást. Az egyetlen módja annak, hogy az alkalmazás a rendszer- és a felhasználói követelményeknek megfelelően működjön próbáld ki!

A tesztelés minden szoftverfejlesztési életciklus kulcsfontosságú eleme, és biztosítja, hogy a szoftver megfelelően és a terveknek megfelelően működjön. A webfejlesztés, a mobilalkalmazás-fejlesztés és a mi kontextusunkban még fontosabb a React alkalmazások ugyanazokat az elveket követik.

A React komponenseket néhány különböző módon lehet tesztelni, nagyjából két csoportra osztva:

  • Alkatrészfák megjelenítése egyszerű tesztkörnyezetben, és állítások a teljesítményükről
  • futás „végpontok közötti tesztek”, amely magában foglalja egy teljes alkalmazás tesztelését valósághű böngészőkörnyezetben

Míg a React alkalmazások tesztelése többféleképpen is elvégezhető, ebben az útmutatóban létrehozunk egy React alkalmazást, és egy teljes útmutatót lefedünk arról, hogyan hajthatunk végre egységteszteket a React alkalmazáson. van és a React tesztelési könyvtár így tökéletesítheti tesztelési készségeit, és megtanulhatja, hogyan hozhat létre szelíd React alkalmazást.

Jegyzet: Hozzáférhet ennek az útmutatónak a tárházához, és ennek segítségével játszhat a benne található tartalommal link a GitHubon.

Mi a tesztelés?

Először is helyezzük perspektívába a dolgokat. Tesztelés nagyon tág fogalom, és utalhat kézi tesztelésre, egységtesztre, regressziós tesztelésre, integrációs tesztelésre, terheléses tesztelésre stb.

Ebben az összefüggésben egység tesztelés amelyekre ma összpontosítunk – teszteljük a megkülönböztető egységek funkciója, jellemzően módszerszinten. Ezzel tesztelhetjük a kimenetek számértékeit, a kimeneti értékek hosszát, alakját, azt, hogy a metódus hogyan reagál az érvénytelen bevitelre stb.

Mivel a legtöbb jó szoftvergyakorlat rövid, végrehajtható módszereket/funkciókat támogat, amelyek önállóan és világos céllal rendelkeznek, sok módszer egyéb módszerek. Általában érdemes mind a belső, mind a külső módszereket tesztelni annak biztosítása érdekében, hogy az átalakítás, a hibák kijavítása vagy a funkciók javítása során végrehajtott változtatások ne sértsenek meg más funkciókat.

In Tesztvezérelt fejlesztés (TDD), javasoljuk, hogy írjon egy tesztet és egy várt értéket, mielőtt egy metódus logikáját megírná. Természetesen elsőre kudarcot vall. Utána azonban csak működésbe kell hozni, és amikor átmegy a teszten, elkezdi átdolgozni, hogy rövidebb, tisztább, gyorsabb stb. legyen. Amíg a kimenet változatlan marad, tudja, hogy nem rontott el semmit. refaktorálás közben!

Saját egységtesztek megírása valakinek a gondolkodásmódjába helyez segítségével a módszereidet, nem pedig valakit írás ezek a módszerek, amelyek gyakran segítenek egy-egy szolgáltatás új pillantást vetni, további ellenőrzéseket és érvényesítést tartalmaznak, valamint hibakeresést végeznek. Néha ez tervezési változtatásokhoz vezet a kód elkészítéséhez tesztelhetőbb, mint például a szétválasztási funkció, amely lehetővé teszi az egyes összetevők numerikus tesztelését.

Miután létrejött az alapvonal, és a kód megfelelt a teszteken, módosíthatja, és ellenőrizheti, hogy az egyes egységek (általában módszerek) külön-külön működnek-e. A tesztelés különösen akkor hasznos, ha frissítések vannak a kódbázisban.

A tesztelés megközelítései

A tesztelést két különböző módon lehet elvégezni: kézzel és a automatikusan. Egy alkalmazással való közvetlen interakció révén a kézi tesztelés ellenőrzi, hogy megfelelően működik-e. Az automatizált tesztelés az a gyakorlat, hogy olyan programokat írnak, amelyek elvégzik az ellenőrzéseket.

Kézi tesztelés

A legtöbb fejlesztő manuálisan ellenőrzi a kódját, mivel ez a leggyorsabb, legtermészetesebb és legegyszerűbb módja a funkciók gyors tesztelésének.

A kézi tesztelés a következő logikus lépés, amely a funkció megírása után következik, hasonlóan ahhoz, ahogy egy étel megkóstolása a fűszerezés (egy funkció hozzáadása) után következik be, hogy ellenőrizze, megfelelően működik-e.

Tételezzük fel, hogy alkalmazott fejlesztőként egy regisztrációs űrlapot készít. Nem kell egyszerűen bezárnia a szövegszerkesztőt, és tájékoztatnia főnökét arról, hogy a kódolás után elkészült az űrlap. Megnyitja a böngészőt, végigmegy a regisztrációs űrlapon, és győződjön meg arról, hogy minden a tervek szerint halad. Más szavakkal, manuálisan teszteli a kódot.

A kézi tesztelés ideális kis projektekhez, és nincs szükség automatizált tesztekre, ha van egy teendőlista-alkalmazása, amelyet kétpercenként manuálisan ellenőrizhet. Attól függően azonban a kézi tesztelés az alkalmazás növekedésével egyre nehezebbé válik – Túl könnyűvé válhat, hogy elveszítjük a koncentrációt, és elfelejtünk ellenőrizni valamit. Egyre bővülő listával kölcsönható összetevők, a kézi tesztelés még nehezebbé válik, különösen, ha már tesztelt valamit, és átlépett egy új elemre, és megszakította az utolsó funkciót, így egy ideig nem teszteli újra, mivel nem tudja, hogy elromlott.

Egyszerűen fogalmazva, a kézi tesztelés megfelelő az induláshoz – de nem skálázódik jól, és nem garantálja a kódminőséget nagyobb projekteknél. A jó hír az, hogy a számítógépek nagyszerűek az ehhez hasonló feladatokban, ezért automatizált tesztelést köszönünk!

Automatizált tesztelés

Az automatizált tesztelés során további kódot ír az alkalmazáskód teszteléséhez. Miután megírta a tesztkódot, megteheti Tesztelje az alkalmazást, ahányszor csak akarja, minimális erőfeszítéssel.

Számos technika létezik az automatizált tesztek írásához:

  • Programok írása a böngésző automatizálására,
  • Funkciók hívása közvetlenül a forráskódból,
  • A megjelenített alkalmazás képernyőképeinek összehasonlítása…

Mindegyik technikának megvannak a maga előnyei, de mindegyikben közös: időt takarítanak meg, és jobb kódminőséget biztosítanak, mint a kézi tesztelés!

Az automatizált tesztek kiválóan alkalmasak annak biztosítására, hogy alkalmazása a tervezettnek megfelelően működjön. Ezenkívül megkönnyítik az alkalmazáson belüli kódmódosítások áttekintését.

A tesztelés típusai

Eddig magas szinten néztük a teszteket. Itt az ideje, hogy megvitassuk a különböző típusú teszteket, amelyeket meg lehet írni.

Háromféle front-end alkalmazásteszt létezik:

  • Mértékegységek: Az egységteszteknél a szoftver egyes egységeit vagy összetevőit tesztelik. Az egyedi egység egyetlen funkció, módszer, eljárás, modul, komponens vagy objektum. Az egységteszt elkülöníti és ellenőrzi a kód egy részét annak ellenőrzése érdekében, hogy a szoftverkód minden egysége a várt módon működik-e.
    Az egyes modulokat vagy funkciókat egységteszttel tesztelik, hogy megbizonyosodjanak arról, hogy megfelelően működnek-e, ahogy kellene, és minden alkatrészt külön-külön is tesztelnek. Az egységteszt magában foglalhatja például annak meghatározását, hogy egy függvény, utasítás vagy ciklus megfelelően működik-e egy programban.

  • Pillanatfelvétel tesztek: Ez a teszttípus biztosítja, hogy a webalkalmazás felhasználói felülete (UI) ne változzon váratlanul. Rögzíti egy komponens kódját egy adott időpontban, lehetővé téve számunkra, hogy az egyik állapotú összetevőt összehasonlítsuk bármely más lehetséges állapottal.
    Egy tipikus pillanatkép-tesztelési forgatókönyv magában foglalja egy UI-összetevő renderelését, pillanatfelvétel készítését, és a pillanatfelvétel összehasonlítását a teszttel együtt tárolt referencia-pillanatkép-fájllal. Ha a két pillanatkép eltér, a teszt sikertelen lesz, mert a változás vagy váratlan volt, vagy a referencia pillanatképet frissíteni kellett, hogy az tükrözze az új felhasználói felület összetevőt.

  • Végpontok közötti tesztek: A végpontok közötti tesztek a legkönnyebben megérthető tesztek. Az előtér-alkalmazások teljes körű tesztjei automatizálják a böngészőt, hogy biztosítsák az alkalmazás megfelelő működését a felhasználó szemszögéből.
    A végpontok közötti tesztek sok időt takarítanak meg. Egy végponttól végpontig terjedő tesztet annyiszor futtathat, ahányszor csak akar, miután megírta. Fontolja meg, hogy mennyi időt takaríthat meg egy több száz ilyen tesztből álló csomag az egyes egységekhez tartozó tesztek megírásához képest.
    Az általuk nyújtott összes előny mellett a teljes körű teszteknek van néhány problémája. Kezdetnek a végpontok közötti tesztek időigényesek. A végpontok közötti tesztekkel kapcsolatos másik probléma az, hogy nehéz lehet hibakeresésük.

Jegyzet: A reprodukálhatósági problémák elkerülése érdekében a végpontok közötti tesztek reprodukálható környezetben, például Docker konténer. A Docker-tárolók és a végpontok közötti tesztek kívül esnek ezen útmutató hatókörén, de érdemes ezeket megvizsgálni, ha végpontok közötti teszteket szeretne futtatni, hogy elkerülje a különböző gépeken jelentkező meghibásodások problémáját.

Ha szeretné megragadni a Cypress-szel végzett teljes körű tesztelés alapjait – olvassa el a mi oldalunkat „Teljes tesztelés JavaScriptben Cypress segítségével”!

A tesztelés előnyei és hátrányai

Bár a tesztelés fontos, és szokás szerint el kell végezni, ennek előnyei és hátrányai egyaránt vannak.

Előnyök

  • Megóv a váratlan regressziótól
  • A megfelelő tesztelés jelentősen javítja a kód minőségét
  • Lehetővé teszi a fejlesztő számára, hogy a múlt helyett az aktuális feladatra koncentráljon
  • Lehetővé teszi az egyébként nehezen megépíthető alkalmazások moduláris felépítését
  • Kiküszöböli a kézi ellenőrzés szükségességét

Hátrányok

  • A hibakeresésen és karbantartáson kívül több kódot kell írnia, és sokan úgy érzik, hogy ez felesleges többletköltség a kisebb projekteknél, függetlenül az előnyöktől
  • A nem kritikus/jóindulatú teszthibák az alkalmazás elutasítását eredményezhetik a folyamatos integráció során

Az egységteszt áttekintése

Eddig általánosságban vettük szemügyre a tesztelést. Itt az ideje, hogy belevessünk mindent, ami az egységteszttel kapcsolatos, és hogyan írjunk egységteszteket a React alkalmazásokban!

Az egységteszt definiálása előtt meg kell értenünk, hogy jó tesztelési megközelítés célja a fejlesztési idő felgyorsítása, az alkalmazások hibáinak csökkentése és a kód minőségének javítása, míg a rossz tesztelési megközelítés megbénítaná az alkalmazást. Ennek eredményeként nekünk, szoftverfejlesztőknek meg kell tanulnunk a hatékony egységtesztelési módszereket, és ezek egyike az egységtesztelés.

A tesztelés egyszerű definíciója az, hogy ez egy alkalmazás megfelelő működésének ellenőrzése. Az egységtesztelés egy alkalmazás összetevőinek vagy funkcióinak tesztelésének folyamata. Az egységtesztek olyan függvények, amelyek a forráskód függvényeinek izolált verzióit hívják meg annak ellenőrzésére, hogy azok determinisztikusan úgy viselkednek-e, ahogyan kell.

Az egységtesztek előnyei

Az egységtesztek gyorsak, és néhány másodperc alatt lefuttathatók (egyenként egy új funkcióhoz vagy globálisan az összes teszt futtatásával), így a fejlesztők azonnali visszajelzést kapnak arról, hogy egy funkció meghibásodott-e vagy sem. Segítenek a dokumentációban is, mert ha új fejlesztő csatlakozik egy projekthez, akkor tudnia kell, hogyan viselkednek a kódbázis különböző egységei; ezt az egységtesztek eredményeiből ismerhetjük meg.

Az egységtesztek hátrányai

Míg az egységteszteknek megvannak a jó oldalai, megvannak a maguk problémái is. Probléma az, hogy a kód átalakításáról van szó tervezési változások, mivel ezek általában nehezebbek az egységtesztekkel. Tegyük fel például, hogy van egy bonyolult funkciója az egységtesztekkel, és ezt a funkciót több moduláris funkcióra szeretné felosztani. Az egységteszt valószínűleg sikertelen lesz az adott függvénynél, ezért elavultnak kell lennie, és két egységtesztet kell írnia az osztott függvényekhez. Ez az oka annak, hogy az egységtesztelés implicit módon ösztönzi azok előzetes felosztását és egyenkénti tesztelését, ami jobban tesztelhető, moduláris kódösszetevőket eredményez. Ennek ellenére bizonyos esetekben nem lehet előre látni a lehetséges változásokat, és az egységtesztek frissítéséhez szükséges idő kevésbé vonzóvá teszi a komoly átalakítási folyamatokat.

Egy másik probléma az egységteszttel, hogy csak az alkalmazás egyes részeit ellenőrzi, még akkor is, ha az a rész több kisebb rész logikai kombinációja – nincs egységteszt a teljes alkalmazásra. Előfordulhat, hogy az alkalmazás egyes részei megfelelően működnek, de ha nem tesztelik, hogyan viselkednek kombinálva, akkor a tesztek használhatatlanná válhatnak. Éppen ezért az egységteszteket ki kell egészíteni végponttól végpontig terjedő tesztekkel vagy integrációs tesztekkel, vagy ideális esetben mindkettővel.

Egy React alkalmazás egységtesztelése – Demo projekt

Nézzünk egy valós példát a React alkalmazás egységtesztjére!

Ebben a demóban egy Counter alkalmazást fogunk tesztelni, sok különböző részből. Annak ellenére, hogy meglehetősen egyszerű alkalmazásnak hangzik, jó példa lehet az egységtesztelés működésének megismerésére. Az alkalmazás tesztelésének lényege, hogy az összetevőnek különböző aspektusai vannak, amelyek attól függnek, hogy a felhasználó hogyan kommunikál vele.

Projekt beállítása

A create-react-app A React csapat által épített parancs a legjobb módja annak, hogy elkezdhessünk egy valós és nagyszabású React alkalmazást, mert készen áll a használatra, és könnyen működik a Jest tesztelési könyvtár. Ha kinyitod a package.json fájlt, látni fogja, hogy alapértelmezett támogatásunk van van és a React tesztelési könyvtár a setupTests.js fájlt. Így szükség esetén nem kell manuálisan telepítenünk a Jest-et projektünkbe!

Ha még nem használta, futtassa npx, amely későbbi használatra telepíti:

$ npx create-react-app react-unit-tests

Ha már telepítette az eszközt, hozzon létre egy React alkalmazást, és nevezze el react-unit-tests:

$ create-react-app react-unit-tests

Jegyzet: npx legújabb verzióját használja create-react-app, míg egy globálisan telepített verzió esetleg nem. Általában ajánlott az eszközt végigfuttatni npx a legújabb verziók biztosítása érdekében, kivéve, ha szándékosan másik verziót kíván használni.

Ezután belépünk a projektkönyvtárba, és elindítjuk a fejlesztőkiszolgálót:

$ cd react-unit-tests && npm start
// OR
$ cd react-unit-tests && yarn start

Ez megjeleníti az újonnan létrehozott alkalmazásunkat a böngészőben a címen localhost:3000.

Jegyzet: Egy praktikus funkció itt az a hot reloading alapértelmezés szerint támogatott, így nem kell folyamatosan újratöltenie a böngészőt pusztán az új változások megtekintéséhez vagy a manuális telepítéshez nodemon vagy hasonló könyvtárak.

Az ellenkomponens felépítése

A src projektünk könyvtárában hozzon létre egy új fájlt Counter.js. -ban Counter.js, akkor meghatározzuk az összetevő összes részét. A számláló különféle funkcióit tartalmazza majd, többek között increment(), decrement(), restart()és switchSign(), amely kattintáskor a számlálási értéket negatívról pozitívra fordítja. Ezek a függvények a kezdeti számlálási érték manipulálásához jönnek létre (amely támaszként kerül átadásra):


import React, { useState } from "react";

function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount);

  const increment = () => {
    setCount((prev) => prev + 1);
  };

  const decrement = () => {
    setCount((prev) => prev - 1);
  };

  const restart = () => {
    setCount(0);
  };

  const switchSign = () => {
    setCount((prev) => prev * -1);
  };

  return (
    <div>
      <h1>
        Count: <h3>{count}</h3>
      </h1>
      <div>
        <button onClick={increment}>Increment</button>
        <button onClick={decrement}>Decrement</button>
        <button onClick={restart}>Restart</button>
        <button onClick={switchSign}>Switch sign</button>
      </div>
    </div>
  );
}

export default Counter;

Akkor frissíts App.js:


import "./App.css";
import Counter from "./Counter";

function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}

export default App;

Most megtekinthetjük a számláló alkalmazást a böngészőben:

Definitive Guide to Unit Testing in React Applications with Jest and React-Testing PlatoBlockchain Data Intelligence. Vertical Search. Ai.

Tesztek készítése komponensekhez

Hozzunk létre egy tesztfájlt, melynek neve Counter.test.js hogy reprezentálja a Counter komponens tesztjét. Ügyeljen arra is, hogy törölje App.test.js hogy a tesztek futtatása közben ne hozzon létre nem kívánt eredményeket.

Jegyzet: Általános gyakorlat, hogy a tesztfájlokat a következő utótaggal nevezik el .test.js, tükrözi a tesztelt fájl/összetevő nevét. Ez biztosítja a folytonosságot a tesztfájlok között, a módosítások csak a frissítendő kódhoz tartozó fájlokon történnek a módosítások leküldésekor (kevesebb számú összevonási ütközés), és olvasható.

Ezenkívül a tesztfájlok jellemzően a /test könyvtár párhuzamos a forráskód gyökérkönyvtárába, de ez is csapatfüggő.

In Counter.test.js, először importáljuk a Counter komponenst, majd indítsa el a tesztet a describe() függvény az összetevőn belül előforduló összes különböző funkció leírására.

A describe() A funkciót arra használjuk, hogy csoportosítsuk azokat a tesztkészleteket, amelyek egy komponensen különböző módokon előfordulhatnak it() és a test() mód. Ez egyfajta logikai burkolóanyag, amelyben leírod, mit csinálnak egy tesztsorozat mindegyikével it() egy egység funkcionális tesztje.

A React-összetevők tesztelése történhet oly módon, hogy a grafikus felhasználói felület generálása helyett tesztrenderer segítségével gyorsan létrehozhatunk egy sorosozható értéket a React-fához, amely a teljes alkalmazás létrehozásával járna.

A kezdeti számlálóérték tesztelése

A tesztelés során segít szisztematikus listát készíteni egy adott szolgáltatás jellemzőiről és szempontjairól – az összetevők állapotairól, azok esetleges befolyásolásáról stb.

Az első dolog, amit tesztelni fogunk, az kezdeti számlálási érték és hogyan kezeli az összetevő az azt beállító kelléket. A ... val it() módszerrel ellenőrizzük, hogy a számlálóalkalmazás valóban azt a pontos kezdeti számlálóértéket jeleníti-e meg, amelyet támaszként adtak át, ami 0 ebben az esetben, és adjon át egy visszahívási függvényt, amely leírja a teszten belül előforduló összes műveletet:


import { render, screen } from "@testing-library/react";
import Counter from "./Counter";

describe(Counter, () => {
  it("counter displays correct initial count", () => {
    render(<Counter initialCount={0} />);
    expect(screen.getByTestId("count").textContent).toEqual(0);
  });
});

Itt használtuk a screen példányt a React Testing könyvtárból az összetevő megjelenítéséhez tesztelési célokra. Hasznos a tesztelendő összetevő álverziójának megjelenítése. És mivel a

elem, amely a count érték dinamikusan változik, használjuk a screen.getByTestId() funkcióval meghallgathatja, és lekérheti az értékét a textContent ingatlan.

Tekintse meg gyakorlatias, gyakorlati útmutatónkat a Git tanulásához, amely tartalmazza a bevált gyakorlatokat, az iparág által elfogadott szabványokat és a mellékelt csalólapot. Hagyd abba a guglizást a Git parancsokkal, és valójában tanulni meg!

Jegyzet: A screen A függvény minden lekérdezéshez megfelelő DOM-csomópontot ad vissza, vagy hibát ad, ha nem található elem.

Aztán a Counter.js komponenst, meghallgatjuk a

elem tesztelés közben a beállításával data-testid attribútumot az értékkel rendelkező elemhez count:


import React, { useState } from "react";

function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount);
  const increment = () => {
    setCount((prev) => prev + 1);
  };
  const decrement = () => {
    setCount((prev) => prev - 1);
  };
  const restart = () => {
    setCount(0);
  };
  const switchSign = () => {
    setCount((prev) => prev * -1);
  };

  return (
    <div>
      <h1>
      	
        Count: <h3 data-testid="count">{count}</h3>
      </h1>
      <div>
        <button onClick={increment}>Increment</button>
        <button onClick={decrement}>Decrement</button>
        <button onClick={restart}>Restart</button>
        <button onClick={switchSign}>Switch sign</button>
      </div>
    </div>
  );
}

export default Counter;

Annak tesztelésére, hogy a kezdeti count érték egyenlő 0, használjuk a expect() módszerrel írjuk le, hogy mi várható az általunk beállított teszttől! Esetünkben azt várjuk, hogy a kezdeti számlálási érték ez lesz 0 így használjuk a toEqual() módszerrel, amellyel meghatározható, hogy két objektum értéke egyezik-e. Az objektum azonosságának meghatározása helyett a toEqual() A matcher rekurzívan ellenőrzi az összes mező egyenlőségét.

Jegyzet: A teszt kifejezetten az Ön által megjelenített információkra összpontosít; példánkban, vagyis a Counter komponens, amely egy initialCount támaszt. Ez arra utal, hogy még ha egy másik fájl is – mondjuk, tegyük App.js– hiányzó kellékei vannak a Counter komponens, a teszt továbbra is sikeres lesz, mert kizárólag erre összpontosít Counter.js és nem tudja, hogyan kell használni a Counter összetevő. Ezen túlmenően, mivel a tesztek függetlenek egymástól, ugyanazon komponens más tesztekben való megjelenítése különböző kellékekkel sem lesz hatással.

Most lefuttathatjuk a beállított tesztet:

$ yarn test

A tesztnek sikertelennek kell lennie:

FAIL  src/Counter.test.js
  Counter
    × counter displays correct initial count (75 ms)

  ● Counter › counter displays correct initial count

    expect(received).toEqual(expected) // deep equality

    Expected: 0
    Received: "0"

       5 |   it("counter displays correct initial count", () => {
       6 |     render();
    >  7 |     expect(screen.getByTestId("count").textContent).toEqual(0);
         |                                                     ^
       8 |   });
       9 | });
      10 |

      at Object. (src/Counter.test.js:7:53)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        1.929 s, estimated 2 s
Ran all test suites related to changed files.

Ez a teszt nem sikerült, mert teszteltünk egy számot egy karakterlánchoz képest, aminek eredményeként a mély egyenlőségi hiba. A javításhoz öntött a textContent, azaz a kezdeti érték a visszahívási függvényünkben számként:


import { render, screen } from "@testing-library/react";
import Counter from "./Counter";

describe(Counter, () => {
  it("counter displays correct initial count", () => {
    render(<Counter initialCount={0} />);
     
    expect(Number(screen.getByTestId("count").textContent)).toEqual(0);
  });
});

Most a kódunk átmegy az első teszten:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (81 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.271 s
Ran all test suites related to changed files.

Ez egy egyszerű példa a tesztelésre míg Az írási logika segít elkerülni a problémákat, mielőtt a technológiai adósság tovább halmozódna. Az idő előtti tesztelés is bezárhatja az embert, mivel az újrafaktorálás és a logika megváltoztatása időbelileg költségesebb, ha a teszteket is újra kell írni.

A jó egyensúly megtalálása segíthet a szoftver minőségének javításában, minimális negatív hatással a termelékenységre és a sebességre.

A Növelés gomb tesztelése

Ennek tesztelésére a increment gomb úgy működik, ahogy kell, vagyis növeli a count értékét eggyel minden alkalommal, amikor rákattintunk, először el kell érnünk a increment gombot, akkor definiálunk egy újat it() módszer ugyanerre.

Mivel a gomb értéke nem dinamikus, vagyis mindig meglesz az értéke Increment belül használjuk a getByRole() módszer helyett getByTestId() a DOM lekérdezéséhez.

Amikor a getByRole() metódus esetén a szerepkör egy HTML elemet ír le.

Egy objektumot is át kell adnunk annak meghatározásához, hogy melyik gombot, különösen melyik gombot szeretnénk tesztelni, mivel sok gomb lehet a DOM megjelenítésekor. Az objektumban beállítjuk a name olyan értékkel, amelynek meg kell egyeznie a növelő gomb szövegével.

A következő teendő egy kattintási esemény szimulálása a fireEvent() módszer, amely lehetővé teszi olyan események aktiválását, amelyek a tesztelés során szimulálják a felhasználói műveleteket.

Először írunk egy tesztet, hogy megnézzük, nő-e a számlálási érték 1-gyel a kezdeti 0-hoz képest:


import { fireEvent, render, screen } from "@testing-library/react";
import Counter from "./Counter";

describe(Counter, () => {
  it("counter displays correct initial count", () => {
    render(<Counter initialCount={0} />);
    expect(Number(screen.getByTestId("count").textContent)).toEqual(0);
  });

  it("count should increment by 1 if increment button is clicked", () => {
    render(<Counter initialCount={0} />);
    fireEvent.click(screen.getByRole("button", { name: "Increment" }));
    let countValue = Number(screen.getByTestId("count").textContent);
    expect(countValue).toEqual(1);
  });
});

Ennek eredményeként:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (79 ms)
    √ count should increment by 1 if increment button is clicked (66 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.405 s
Ran all test suites related to changed files.

Ezután tesztet is írhatunk annak ellenőrzésére, hogy a count érték 0 volt, mielőtt a gombra kattintott volna kettő megadásával expect() módszerek – az egyik a kattintási esemény elindítása előtt, a másik pedig a kattintási esemény aktiválása után:


it("count should increment by 1 if increment button is clicked", () => {
    render(<Counter initialCount={0} />);
    let countValue1 = Number(screen.getByTestId("count").textContent);
    expect(countValue1).toEqual(0);
    fireEvent.click(screen.getByRole("button", { name: "Increment" }));
    let countValue2 = Number(screen.getByTestId("count").textContent);
    expect(countValue2).toEqual(1);
});

A tesztek még sikeresek voltak:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (82 ms)
    √ count should increment by 1 if increment button is clicked (60 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.388 s
Ran all test suites related to changed files.

A Csökkentő gomb tesztelése

Ugyanígy megírtuk a tesztet a Increment gombot, meghatározzuk a tesztet a Decrement gomb így:


it("count should decrement by 1 if decrement button is clicked", () => {
  render(<Counter initialCount={0} />);
  fireEvent.click(screen.getByRole("button", { name: "Decrement" }));
  let countValue = Number(screen.getByTestId("count").textContent);
  expect(countValue).toEqual(-1);
});

Ennek eredményeként:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (79 ms)
    √ count should increment by 1 if increment button is clicked (73 ms)
    √ count should decrement by 1 if decrement button is clicked (21 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        2.346 s
Ran all test suites related to changed files.

Az Újraindítás gomb tesztelése

Hasonló a Increment és a Decrement gombok esetén meghatározzuk a tesztet a Restart gomb így:


it("count should reset to 0 if restart button is clicked", () => {
  render(<Counter initialCount={50} />);
  fireEvent.click(screen.getByRole("button", { name: "Restart" }));
  let countValue = Number(screen.getByTestId("count").textContent);
  expect(countValue).toEqual(0);
});

Tesztelés céljából a kezdeti értéket 50-re állítottuk (tetszőleges érték), és a teszt futtatásakor mind a négy teszt sikeresen teljesít:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (81 ms)
    √ count should increment by 1 if increment button is clicked (57 ms)
    √ count should decrement by 1 if decrement button is clicked (21 ms)
    √ count should reset to 0 if restart button is clicked (16 ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        2.583 s
Ran all test suites related to changed files.

A Switch Sign gomb tesztelése

Az előjel megfordításának tesztjét is felírjuk a count érték beállításával count 50-re a tesztfájlban. Ezután nézze meg, hogy milyen jel jelenik meg a gomb által elindított kattintási esemény előtt és után:


it("count invert signs if switch signs button is clicked", () => {
  render(<Counter initialCount={50} />);
  let countValue1 = Number(screen.getByTestId("count").textContent);
  expect(countValue1).toEqual(50);
  fireEvent.click(screen.getByRole("button", { name: "Switch signs" }));
  let countValue2 = Number(screen.getByTestId("count").textContent);
  expect(countValue2).toEqual(-50);
});

Ennek eredményeként:

$ yarn test

PASS  src/Counter.test.js
  Counter
    √ counter displays correct initial count (91 ms)
    √ count should increment by 1 if increment button is clicked (72 ms)
    √ count should decrement by 1 if increment button is clicked (21 ms)
    √ count should reset to 0 if restart button is clicked (19 ms)
    √ count invert signs if switch signs button is clicked (14 ms)

Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        3.104 s
Ran all test suites related to changed files.

Wooshh! A számlálóalkalmazásunk összes tesztje sikeresen lezajlott.

A tesztek megírása nem nehéz – hatékonyan szimuláljuk egy funkció használati eseteit, hogy megbizonyosodjunk arról, hogy nem törik el, ha rendeltetésszerűen és nem szándékosan használják. Valaki adott határon túli értéket? Rossz formátum? Az alkalmazásnak meg kell oldania a problémát a sikertelenség helyett.

Általában jó kiindulópont a teszteléshez:

  • Tesztelje a tervezett viselkedést (bármilyen jellemzői is vannak)
  • Tesztelje a nem kívánt viselkedés minden oldalát (rossz bevitel, például nem támogatott formátumok, határok stb.)
  • Tesztelje numerikusan (ha a jellemzője ellenőrizhető számértékeket produkál, számítsa ki kézzel az eredményt, és ellenőrizze, hogy a megfelelő kimenetet adja-e vissza)

Az egységtesztelés bevált gyakorlatai

  • A teszteknek determinisztikusnak kell lenniük: Ugyanazon tesztek többszöri futtatása ugyanazon a komponensen minden alkalommal ugyanazt az eredményt adja. Gondoskodnia kell arról, hogy az előállított pillanatképek ne tartalmazzanak platform-specifikus vagy más nem determinisztikus adatokat.

  • Kerülje a szükségtelen teszteket: A jó tesztek nem járnak felesleges elvárásokkal vagy tesztesetekkel.
    Jobb megértést kaphatunk, ha megnézzük az alábbi teszteket:

test('the success modal is visible', () => {});
test('the success modal has a success message', () => {});

Ha tudjuk, hogy a sikerüzenet a sikermódon belül látható, akkor ez azt jelenti, hogy maga a sikermodál is látható. Tehát ebben az esetben nyugodtan eltávolíthatjuk az első tesztet, és csak a másodikat hajthatjuk végre, vagy kombinálhatjuk őket. A sok teszt hamis biztonságérzetet kelthet, ha feleslegesek.

  • Kerülje a belső logika feltárását: Ha a teszt olyan műveletet hajt végre, amelyet a felhasználó nem (például olyan belső módszert tesztel, amely nem látható a felhasználó számára), akkor valószínűleg a megvalósítás részleteit teszteli. Előfordulhat, hogy egy privát funkciót kizárólag az összetevő tesztelése érdekében tesz közzé. Ez egy kódszag, amelyet el kell kerülni. Ehelyett alakítsa át kódbázisát úgy, hogy a privát funkció tesztelhető legyen anélkül, hogy nyilvánosan közzétenné.

  • Kerülje a megvalósítás részleteinek tesztelését: Ha az alkalmazásunk növekszik x és a y - hogy x előbb nő, vagy nem valószínű, hogy nincs jelentősége, mindaddig, amíg az eredmény ugyanaz. Mindig képesnek kell lennie a megvalósítás részleteinek átdolgozására, megváltoztatására és egyéb módon történő frissítésére anélkül, hogy megtörné a teszteket, ellenkező esetben a tesztek katalizálnák a technológiai adósság felhalmozódását azáltal, hogy növelik az átalakítás és az optimalizálás költségeit.

  • Helyezze az üzleti logikát tiszta funkciókba a felhasználói felület összetevői helyett.

Következtetés

Ez az útmutató elsősorban az egységtesztről szól. Fontos volt azonban, hogy először megértsük és értékeljük mindazt, ami a tesztelést magában foglalja, beleértve a jelentését, a tesztelés megközelítéseit, a tesztelés típusait, valamint előnyeit és hátrányait.

Nagyon fontos, hogy ne feledje, miért ír teszteket írás közben. A tesztírás célja általában az időmegtakarítás. A tesztek megtérülnek, ha a projekt, amelyen dolgozik, stabil, és hosszú ideig fejlesztik. Ezzel nyugodtan kijelenthetjük, hogy egy alkalmazás tesztelése nem éri meg, ha nem takarít meg fejlesztési időt. Mindenekelőtt a jó tesztek egyszerűen karbantarthatók, és biztonságot nyújtanak a kód megváltoztatásakor.

Azt is megtanultuk, hogyan lehet lekérdezni a DOM-ot, miközben a React alkalmazásokat teszteltük a getByTestId() módszer. Hasznos a konténerek meghatározásához és a dinamikus szöveges elemek lekérdezéséhez, de nem ez lehet az alapértelmezett lekérdezés. Ahelyett, hogy a getByTestId() módszert, először próbálja ki az alábbiak egyikét:

  • getByRole() – lekérdez egy elemet, miközben gondoskodik arról is, hogy a megfelelő szereppel és szöveggel elérhető legyen
  • getByLabelText() – kiváló lekérdezés az űrlapelemekkel való interakcióhoz, emellett ellenőrzi, hogy a címkéink megfelelően kapcsolódnak-e a bemeneteinkhez a for és id attribútumokon keresztül
  • getByText() – Ha az előző két lekérdezés egyike sem érhető el, a getByText() módszer hasznos lesz a felhasználó számára látható szövegen alapuló elemek eléréséhez
  • getByPlaceholderText(): Ez a lekérdezés nagyon előnyösebb, mint egy tesztazonosító, amikor egy elem lekérdezéséhez csak egy helyőrző kell.

Reméljük, hogy ez az útmutató hasznos az Ön számára! Hozzáférhet ennek az útmutatónak a tárházához, és ennek segítségével játszhat a benne található tartalommal link a GitHubon.

Időbélyeg:

Még több Stackabus