Jest testavimo framework JavaScript aplikacijoms

Kodėl Jest tapo tokiu populiariu pasirinkimu

Kai prieš kelerius metus pradėjau rimčiau domėtis JavaScript testavimu, rinkoje buvo tikras chaosas. Mocha, Jasmine, Karma, QUnit – galvą suk nuo pasirinkimų gausos. Kiekvienas framework’as reikalavo savų konfigūracijų, papildomų bibliotekų assertion’ams, mock’ų sistemų. Tada atsirado Jest, ir viskas pasikeitė.

Facebook komanda sukūrė Jest kaip atsaką į realias problemas, su kuriomis susiduria kūrėjai kasdien. Jie norėjo framework’o, kuris veiktų iš dėžės be valandų trunkančių konfigūracijų. Ir jiems pavyko – Jest ateina su assertion biblioteka, mock’ų sistema, code coverage įrankiais ir net snapshot testavimu. Viskas vienoje vietoje.

Kas iš tikrųjų padarė Jest tokį populiarų, tai ne tik funkcionalumas. Tai greitis ir paprastumas. Zero-config filosofija reiškia, kad daugeliu atvejų galite tiesiog įdiegti Jest ir pradėti rašyti testus. Nereikia kelių dienų konfigūruoti webpack’o, babel’io ir kitų įrankių tarpusavio sąveiką.

Kaip pradėti su Jest be galvos skausmo

Įdiegti Jest yra juokingai paprasta. Jei dirbate su npm, tiesiog paleiskite:

npm install --save-dev jest

Arba su yarn:

yarn add --dev jest

Dabar package.json faile pridėkite test script’ą:

"scripts": {
"test": "jest"
}

Ir viskas. Rimtai. Dabar galite kurti failus su .test.js arba .spec.js pabaigomis, ir Jest juos automatiškai ras bei paleisis.

Paprastas pavyzdys atrodytų taip. Tarkime, turite funkciją sum.js:

function sum(a, b) {
return a + b;
}
module.exports = sum;

Jūsų testas sum.test.js būtų:

const sum = require('./sum');

test('sudeda 1 + 2 ir gauna 3', () => {
expect(sum(1, 2)).toBe(3);
});

Paleiskite npm test ir matote žalią varnelę. Jei testas nepraeitų, gautumėte labai aiškų pranešimą, kur ir kas nepavyko.

Matchers sistema ir kaip ja naudotis protingai

Jest matcher’iai – tai komandos, kuriomis sakote, ko tikitės iš savo kodo. Pradedantieji dažnai naudoja tik toBe() ir toEqual(), bet Jest turi dešimtis įvairių matcher’ių, kurie daro testus skaitomesnius ir tikslesnius.

toBe() naudoja Object.is() lygybei patikrinti – tai reiškia, kad jis tikrina griežtą lygybę. Objektams ir masyvams geriau naudoti toEqual(), kuris rekursyviai tikrina visas savybes:

test('objektų lyginimas', () => {
const data = {one: 1};
data['two'] = 2;
expect(data).toEqual({one: 1, two: 2});
});

Yra ir daugiau naudingų matcher’ių. toBeNull(), toBeUndefined(), toBeDefined(), toBeTruthy(), toBeFalsy() – visi jie daro tiksliai tai, ką sako. Skaičiams turime toBeGreaterThan(), toBeLessThan(), toBeCloseTo() (pastarasis naudingas float skaičiams).

String’ams galite naudoti regex’us su toMatch():

test('nėra I žodžje team', () => {
expect('team').not.toMatch(/I/);
});

Masyvams ir iterable objektams yra toContain():

test('pirkinių sąraše yra pienas', () => {
const shoppingList = ['pienas', 'duona', 'kiaušiniai'];
expect(shoppingList).toContain('pienas');
});

Asinchroninio kodo testavimas – kur dauguma suklysta

Čia prasideda tikrasis smagumas. Asinchroninis kodas JavaScript’e yra visur, ir jį testuoti reikia mokėti. Jest palaiko kelis būdus, ir svarbu suprasti, kada kurį naudoti.

Pirmasis būdas – callback’ai. Jei jūsų funkcija naudoja callback’us, perduokite done parametrą į test funkciją:

test('duomenys yra peanut butter', done => {
function callback(data) {
try {
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}
fetchData(callback);
});

Bet atvirai – callback’ai yra 2010-ųjų stilius. Šiais laikais naudojame Promise’us ir async/await. Su Promise’ais tiesiog grąžinkite promise iš testo:

test('duomenys yra peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});

Svarbu: jei negrąžinsite promise, testas baigsis prieš promise resolve’indamasis, ir jūsų assertion’ai niekada nebus patikrinti.

Dar geriau – naudokite async/await. Tai skaitomiausia ir švariausia sintaksė:

test('duomenys yra peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});

Jei tikitės, kad promise bus rejected, naudokite .rejects:

test('fetch nepavyksta su klaida', async () => {
await expect(fetchData()).rejects.toThrow('error');
});

Mock’ai ir spy’ai – kaip testuoti nepriklausomai

Vienas didžiausių Jest privalumų yra integruota mock’ų sistema. Nereikia jokių papildomų bibliotekų kaip Sinon.js. Viskas jau yra.

Mock funkcijos leidžia jums pakeisti tikrąsias funkcijas ir stebėti, kaip jos kviečiamos. Paprasčiausias būdas sukurti mock funkciją:

const mockCallback = jest.fn(x => 42 + x);

test('mock funkcija', () => {
mockCallback(0);
mockCallback(1);

expect(mockCallback).toHaveBeenCalledTimes(2);
expect(mockCallback).toHaveBeenCalledWith(1);
expect(mockCallback).toHaveBeenLastCalledWith(1);
});

Realybėje dažnai reikia mock’inti išorinius modulius. Tarkime, turite modulį, kuris daro API kvietimus. Testuodami nenorite tikrai kviesti API. Jest leidžia lengvai mock’inti visą modulį:

jest.mock('./api');
const api = require('./api');

test('vartotojas gaunamas iš API', async () => {
api.getUser.mockResolvedValue({name: 'Jonas', age: 30});

const user = await getUserData(1);
expect(user.name).toBe('Jonas');
});

mockResolvedValue() yra super patogus būdas mock’inti async funkcijas, kurios grąžina Promise. Yra ir mockRejectedValue() klaidų atvejams.

Kartais reikia mock’inti tik dalį modulio, palikiant likusią dalį tikrą. Naudokite requireActual:

jest.mock('./utils', () => ({
...jest.requireActual('./utils'),
generateId: jest.fn(() => 'test-id-123')
}));

Snapshot testavimas – ar tai stebuklinga kulka ar pinkles

Snapshot testavimas yra viena iš kontroversišiausių Jest funkcijų. Vieni žmonės jį myli, kiti nekenčia. Aš pats esu kažkur per vidurį.

Idėja paprasta: vietoj to, kad rašytumėte dešimtis assertion’ų, Jest išsaugo jūsų komponento išvestį į failą ir palygina ją kiekvieną kartą. Tai ypač populiaru React komponentų testavimui:

import renderer from 'react-test-renderer';
import Button from './Button';

test('Button komponentas', () => {
const tree = renderer.create(

Daugiau

Elasticsearch Logstash pipeline: logų apdorojimas