Eesti

Õpi selgeks testipõhine arendus (TDD) JavaScriptis. See põhjalik juhend käsitleb Red-Green-Refactor tsüklit, praktilist rakendamist Jestiga ning kaasaegse arenduse parimaid praktikaid.

Testipõhine arendus (TDD) JavaScriptis: Põhjalik juhend globaalsetele arendajatele

Kujutage ette sellist stsenaariumi: teie ülesandeks on muuta kriitilist koodilõiku suures pärandsüsteemis. Te tunnete hirmutunnet. Kas teie muudatus rikub midagi muud ära? Kuidas saate olla kindel, et süsteem töötab endiselt ettenähtud viisil? See hirm muudatuste ees on levinud häda tarkvaraarenduses, mis viib sageli aeglase arengu ja habraste rakendusteni. Aga mis siis, kui oleks olemas viis tarkvara enesekindlalt ehitada, luues turvavõrgu, mis püüab vead kinni enne, kui need kunagi produktsiooni jõuavad? See on testipõhise arenduse (TDD) lubadus.

TDD ei ole pelgalt testimistehnika; see on distsiplineeritud lähenemine tarkvara disainile ja arendusele. See pöörab traditsioonilise „kirjuta kood, siis testi“ mudeli pea peale. TDD-ga kirjutate testi, mis ebaõnnestub, enne kui kirjutate produktsioonikoodi, et see läbiks. Sellel lihtsal ümberpööramisel on sügavad tagajärjed koodi kvaliteedile, disainile ja hooldatavusele. See juhend pakub põhjalikku ja praktilist ülevaadet TDD rakendamisest JavaScriptis, mis on mõeldud professionaalsete arendajate globaalsele auditooriumile.

Mis on testipõhine arendus (TDD)?

Oma olemuselt on testipõhine arendus arendusprotsess, mis tugineb väga lühikese arendustsükli kordamisele. Selle asemel, et kirjutada funktsioone ja neid seejärel testida, nõuab TDD, et test kirjutataks esimesena. See test ebaõnnestub vältimatult, kuna funktsiooni pole veel olemas. Arendaja ülesanne on seejärel kirjutada lihtsaim võimalik kood, et see konkreetne test läbiks. Kui see on läbitud, puhastatakse ja täiustatakse koodi. Seda põhitsüklit tuntakse kui „Red-Green-Refactor“ tsüklit.

TDD rütm: Red-Green-Refactor

See kolmeetapiline tsükkel on TDD südametukse. Selle rütmi mõistmine ja harjutamine on tehnika valdamiseks fundamentaalne.

Kui tsükkel on ühe väikese funktsionaalsuse jaoks lõpule viidud, alustatakse uuesti järgmise osa jaoks uue mittetoimiva testiga.

TDD kolm seadust

Robert C. Martin (tihti tuntud kui „Onu Bob“), agiilse tarkvaraliikumise võtmeisik, määratles kolm lihtsat reeglit, mis kodifitseerivad TDD distsipliini:

  1. Te ei tohi kirjutada ühtegi produktsioonikoodi, välja arvatud selleks, et panna läbima mittetoimivat ühiktesti.
  2. Te ei tohi kirjutada ühiktesti rohkem, kui on piisav selle mittetoimimiseks; ja kompileerimisvead on mittetoimimised.
  3. Te ei tohi kirjutada rohkem produktsioonikoodi, kui on piisav ühe mittetoimiva ühiktesti läbimiseks.

Nende seaduste järgimine sunnib teid Red-Green-Refactor tsüklisse ja tagab, et 100% teie produktsioonikoodist on kirjutatud konkreetse, testitud nõude rahuldamiseks.

Miks peaksite TDD kasutusele võtma? Globaalne äriline põhjendus

Kuigi TDD pakub tohutut kasu üksikutele arendajatele, avaldub selle tõeline jõud meeskonna ja äri tasandil, eriti globaalselt hajutatud keskkondades.

JavaScripti TDD keskkonna seadistamine

TDD-ga alustamiseks JavaScriptis on vaja mõnda tööriista. Kaasaegne JavaScripti ökosüsteem pakub suurepäraseid valikuid.

Testimiskomplekti põhikomponendid

Selle lihtsuse ja kõik-ühes olemuse tõttu kasutame oma näidetes Jesti. See on suurepärane valik meeskondadele, kes otsivad „null-konfiguratsiooniga“ kogemust.

Samm-sammuline seadistamine Jestiga

Seadistame uue projekti TDD jaoks.

1. Initsialiseerige oma projekt: Avage oma terminal ja looge uus projektikataloog.

mkdir js-tdd-project
cd js-tdd-project
npm init -y

2. Installige Jest: Lisage Jest oma projekti arendussõltuvusena.

npm install --save-dev jest

3. Konfigureerige testiskript: Avage oma `package.json` fail. Leidke jaotis `"scripts"` ja muutke `"test"` skripti. Samuti on väga soovitatav lisada `"test:watch"` skript, mis on TDD töövoo jaoks hindamatu.

"scripts": {
  "test": "jest",
  "test:watch": "jest --watchAll"
}

`--watchAll` lipp ütleb Jestile, et see käivitaks testid automaatselt uuesti, kui fail salvestatakse. See annab kohest tagasisidet, mis sobib ideaalselt Red-Green-Refactor tsükliga.

Ongi kõik! Teie keskkond on valmis. Jest leiab automaatselt testifailid, mille nimi on `*.test.js`, `*.spec.js`, või mis asuvad `__tests__` kataloogis.

TDD praktikas: `CurrencyConverter` mooduli ehitamine

Rakendame TDD tsüklit praktilisele, globaalselt mõistetavale probleemile: raha konverteerimine valuutade vahel. Ehitame `CurrencyConverter` mooduli samm-sammult.

Iteratsioon 1: Lihtne, fikseeritud kursiga konverteerimine

🔴 RED: Kirjuta esimene mittetoimiv test

Meie esimene nõue on konverteerida konkreetne summa ühest valuutast teise, kasutades fikseeritud kurssi. Looge uus fail nimega `CurrencyConverter.test.js`.

// CurrencyConverter.test.js
const CurrencyConverter = require('./CurrencyConverter');

describe('CurrencyConverter', () => {
  it('should convert an amount from USD to EUR correctly', () => {
    // Arrange
    const amount = 10; // 10 USD
    const expected = 9.2; // Assuming a fixed rate of 1 USD = 0.92 EUR

    // Act
    const result = CurrencyConverter.convert(amount, 'USD', 'EUR');

    // Assert
    expect(result).toBe(expected);
  });
});

Nüüd käivitage testide jälgija oma terminalist:

npm run test:watch

Test ebaõnnestub suurejooneliselt. Jest teatab midagi sarnast: `TypeError: Cannot read properties of undefined (reading 'convert')`. See on meie PUNANE seisund. Test ebaõnnestub, sest `CurrencyConverter` ei eksisteeri.

🟢 GREEN: Kirjuta lihtsaim kood testi läbimiseks

Nüüd teeme testi läbivaks. Looge `CurrencyConverter.js`.

// CurrencyConverter.js
const rates = {
  USD: {
    EUR: 0.92
  }
};

const CurrencyConverter = {
  convert(amount, from, to) {
    return amount * rates[from][to];
  }
};

module.exports = CurrencyConverter;

Niipea kui selle faili salvestate, käivitab Jest testi uuesti ja see muutub ROHELISEKS. Oleme kirjutanud absoluutselt minimaalse koodi, et rahuldada testi nõuet.

🔵 REFACTOR: Täiusta koodi

Kood on lihtne, kuid me saame juba mõelda täiustustele. Pesastatud `rates` objekt on veidi jäik. Praegu on see piisavalt puhas. Kõige tähtsam on see, et meil on töötav funktsioon, mida kaitseb test. Liigume edasi järgmise nõude juurde.

Iteratsioon 2: Tundmatute valuutade käsitlemine

🔴 RED: Kirjuta test kehtetu valuuta jaoks

Mis peaks juhtuma, kui proovime konverteerida valuutasse, mida me ei tunne? See peaks ilmselt viskama vea. Määratleme selle käitumise uues testis failis `CurrencyConverter.test.js`.

// In CurrencyConverter.test.js, inside the describe block

it('should throw an error for unknown currencies', () => {
  // Arrange
  const amount = 10;

  // Act & Assert
  // We wrap the function call in an arrow function for Jest's toThrow to work.
  expect(() => {
    CurrencyConverter.convert(amount, 'USD', 'XYZ');
  }).toThrow('Unknown currency: XYZ');
});

Salvestage fail. Testikäivitaja näitab kohe uut ebaõnnestumist. See on PUNANE, sest meie kood ei viska viga; see üritab ligi pääseda `rates['USD']['XYZ']`, mis põhjustab `TypeError`. Meie uus test on selle vea õigesti tuvastanud.

🟢 GREEN: Pane uus test läbima

Muudame `CurrencyConverter.js` faili, et lisada valideerimine.

// CurrencyConverter.js
const rates = {
  USD: {
    EUR: 0.92,
    GBP: 0.80
  },
  EUR: {
    USD: 1.08
  }
};

const CurrencyConverter = {
  convert(amount, from, to) {
    if (!rates[from] || !rates[from][to]) {
      // Determine which currency is unknown for a better error message
      const unknownCurrency = !rates[from] ? from : to;
      throw new Error(`Unknown currency: ${unknownCurrency}`);
    }
    return amount * rates[from][to];
  }
};

module.exports = CurrencyConverter;

Salvestage fail. Mõlemad testid on nüüd läbivad. Oleme tagasi ROHELISES seisundis.

🔵 REFACTOR: Puhasta koodi

Meie `convert` funktsioon kasvab. Valideerimisloogika on segatud arvutusega. Võiksime valideerimise eraldada eraldi privaatseks funktsiooniks loetavuse parandamiseks, kuid praegu on see veel hallatav. Võti on selles, et meil on vabadus neid muudatusi teha, sest meie testid annavad meile teada, kui me midagi ära rikume.

Iteratsioon 3: Asünkroonne kursipäring

Kurside käsitsi sisestamine pole realistlik. Refaktoorime oma mooduli, et see hangiks kursse (mockitud) välisest API-st.

🔴 RED: Kirjuta asünkroonne test, mis mockib API-kutset

Esiteks peame oma konverteri ümber struktureerima. See peab nüüd olema klass, mida saame instantseerida, võib-olla API-kliendiga. Peame ka `fetch` API-d mockima. Jest teeb selle lihtsaks.

Kirjutame oma testifaili ümber, et see vastaks uuele, asünkroonsele reaalsusele. Alustame uuesti õnneliku stsenaariumi testimisega.

// CurrencyConverter.test.js
const CurrencyConverter = require('./CurrencyConverter');

// Mock the external dependency
global.fetch = jest.fn();

beforeEach(() => {
  // Clear mock history before each test
  fetch.mockClear();
});

describe('CurrencyConverter', () => {
  it('should fetch rates and convert correctly', async () => {
    // Arrange
    // Mock the successful API response
    fetch.mockResolvedValueOnce({
      json: () => Promise.resolve({ rates: { EUR: 0.92 } })
    });

    const converter = new CurrencyConverter('https://api.exchangerates.com');
    const amount = 10; // 10 USD

    // Act
    const result = await converter.convert(amount, 'USD', 'EUR');

    // Assert
    expect(result).toBe(9.2);
    expect(fetch).toHaveBeenCalledTimes(1);
    expect(fetch).toHaveBeenCalledWith('https://api.exchangerates.com/latest?base=USD');
  });

  // We'd also add tests for API failures, etc.
});

Selle käivitamine toob kaasa hulga PUNAST. Meie vana `CurrencyConverter` ei ole klass, sellel pole `async` meetodit ja see ei kasuta `fetch`-i.

🟢 GREEN: Rakenda asünkroonne loogika

Nüüd kirjutame `CurrencyConverter.js` ümber, et see vastaks testi nõuetele.

// CurrencyConverter.js
class CurrencyConverter {
  constructor(apiUrl) {
    this.apiUrl = apiUrl;
  }

  async convert(amount, from, to) {
    const response = await fetch(`${this.apiUrl}/latest?base=${from}`);
    if (!response.ok) {
      throw new Error('Failed to fetch exchange rates.');
    }

    const data = await response.json();
    const rate = data.rates[to];

    if (!rate) {
      throw new Error(`Unknown currency: ${to}`);
    }

    // Simple rounding to avoid floating point issues in tests
    const convertedAmount = amount * rate;
    return parseFloat(convertedAmount.toFixed(2));
  }
}

module.exports = CurrencyConverter;

Salvestamisel peaks test muutuma ROHELISEKS. Pange tähele, et lisasime ka ümardamisloogika, et tegeleda ujukomaarvude ebatäpsustega, mis on levinud probleem finantsarvutustes.

🔵 REFACTOR: Täiusta asünkroonset koodi

`convert` meetod teeb palju: pärimine, veakäsitlus, parsimine ja arvutamine. Võiksime selle refaktoorida, luues eraldi `RateFetcher` klassi, mis vastutab ainult API-suhtluse eest. Meie `CurrencyConverter` kasutaks siis seda pärimisklassi. See järgib ühe vastutuse printsiipi ja muudab mõlemad klassid lihtsamini testitavaks ja hooldatavaks. TDD juhatab meid selle puhtama disaini poole.

Levinud TDD mustrid ja antimustrid

TDD-d praktiseerides avastate mustreid, mis töötavad hästi, ja antimustreid, mis tekitavad hõõrdumist.

Head mustrid, mida järgida

Antimustrid, mida vältida

TDD laiemas arenduse elutsüklis

TDD ei eksisteeri vaakumis. See integreerub kaunilt kaasaegsete Agile ja DevOps praktikatega, eriti globaalsete meeskondade jaoks.

Kokkuvõte: Sinu teekond TDD-ga

Testipõhine arendus on rohkem kui testimisstrateegia—see on paradigma nihe selles, kuidas me läheneme tarkvaraarendusele. See soodustab kvaliteedi, enesekindluse ja koostöö kultuuri. Red-Green-Refactor tsükkel pakub stabiilset rütmi, mis juhatab teid puhta, robustse ja hooldatava koodi poole. Tulemuseks olev testikomplekt muutub turvavõrguks, mis kaitseb teie meeskonda regressioonide eest, ja elavaks dokumentatsiooniks, mis aitab uusi liikmeid sisse elada.

Õppimiskõver võib tunduda järsk ja algne tempo võib tunduda aeglasem. Kuid pikaajalised dividendid vähendatud silumisaja, parema tarkvaradisaini ja suurenenud arendajate enesekindluse näol on mõõtmatud. Tee TDD valdamiseni on distsipliini ja praktika küsimus.

Alusta juba täna. Vali oma järgmises projektis üks väike, mittekriitiline funktsioon ja pühendu protsessile. Kirjuta test esimesena. Vaata, kuidas see ebaõnnestub. Tee see läbivaks. Ja siis, mis kõige tähtsam, refaktoori. Kogege enesekindlust, mis kaasneb rohelise testikomplektiga, ja te imestate varsti, kuidas te kunagi tarkvara teisiti ehitasite.

Testipõhine arendus (TDD) JavaScriptis: Põhjalik juhend globaalsetele arendajatele | MLOG