Галоўная / Артыкулы

Тэставанне модуляў на JavaScript за дапамогай Jest і Vitest: практыкі, якія застаюцца эфектывнымі

Як правільна перацовка тэстаў на JavaScript: што належыць да ўзелковага слоя, Vitest проты Jest проты Mocha, падход arrange-act-assert, мокі, крайнія кейсы, CI, і дзе дапамага AI.

Выдавец: REACTAPP.TOP7 хв чытання1573 слоў

Крыніцы: JavaScript Unit Testing Best Practices: A Practical Guide with Jest and Vitest Examples

Тэсты на адзінкі выдзеляюць самыя маленькіе элементы, якія можна працаваць — функцыі, методы, класы — і пераканальваюцца, што яны правільна працуюць. Яны знаходзяцца у основе піраміды тэставання, таму яны должны адражаць рэальную бізнес-логіку і рэальныя рызыкі, а не тэрмінологію.

Апоўнаючыся практыкамі промышленасці, тут прэдставлена практычная аднарада па эфектывнам тэставанні на адзінкі ў JavaScript.

Што робіць тэст на адзінкі хорашым?

Хорашыя тэсты на адзінкі пераканальваюцца рэзультатамі, а не прыватнымі способамі рэалізацыі. Гэта дапамагае захаваць стабільнасць набору тэстаў пад час рэфакторавання внутрошняй часты коду.

Характэрыстыкі, якія павтараюцца ўсё часта:

  • Шырокі — за мілісекунды. Медленныя наборы тэстаў не запускаюцца пры зберэжэнні змян.
  • Ізольаваны — без залежнасці ад стану паказвальных тэстаў; можна безбедна перасортаваць іх адночасова.
  • Дэтэрміністычны — адносна тое ж рэзультата ў кожны раз, колі яго запускаюць. Рэзультат «локальна успех» / «у CI неудача» означае ненадзейнасць тэста, а такія тэсты разрушаюць довер'е.
  • Чытальнае — гэты набор являецца дынамічнымі документамі. Новачаку трэба выучыць адпаведную працю набору толькі на адварынку тэстаў.
  • Прыклад структуры:

    // A clean, predictable unit test using Jest/Vitest syntax
    describe('calculateTotalWithTax', () => {
      it('should apply a standard 10% tax rate to the subtotal', () => {
        // Arrange
        const subtotal = 100;
        const taxRate = 0.10;
    
        // Act
        const result = calculateTotalWithTax(subtotal, taxRate);
    
        // Assert
        expect(result).toBe(110);
      });
    
      it('should throw an explicit error if the subtotal is negative', () => {
        expect(() => calculateTotalWithTax(-50, 0.10)).toThrow('Invalid subtotal');
      });
    
      it('should return the subtotal unchanged when tax rate is 0', () => {
        // Edge case: no tax applied
        expect(calculateTotalWithTax(100, 0)).toBe(100);
      });
    
      it('should round to 2 decimal places to avoid floating-point errors', () => {
        // Guards against bugs like 19.99 * 1.10 = 21.989000000000004
        expect(calculateTotalWithTax(19.99, 0.10)).toBe(21.99);
      });
    });
    

    Што належыць (і што не належыць)

    Зберагаюце ўніт-тэсты чыстымі, так каб цяплая стрэлка означала паўстанак бізнес-логікі. Усе іншае належыць да вышэйшых роўней піраміды.

    Структура піраміды: многа быстрых уніт-тэстоў у ніжней частцы, менша колькасць інтэграцыйных тэстоў у серэдзіне, тонкі слой E2E на верхней частцы. Якшо перакрысіце ўсё гэта, вы отрымаеце медленныя, ненадзейныя, дорогія наборы тэстаў.

    Што належыць у ўніт-тэстах

    Няма I/O, няма побачных эфектаў, няма залежнасцей, якімі вы не керуеце:

    • Чыстыя функціі (калькуляторы податкаў, фарматары, парсеры дат, механізмы зніжак)
    • Трансформацыі (map/filter/sort, API → view-model)
    • Бізнес-правіла (валідацыя, рангі цэнаў, апштрыкты праваў) — крайнія прыклады знаходзяцца тут, а ўніт-тэсты являюцься дыяўергентным рашэнням
  • Аўтаномны стан UI, заданный пропамі/стацыямі, незалежны ад суседніх элементаў DOM чы жывага бэкенду
  • Калі вы можэце сказаць «з урахованнем гэтых вводных, магчыма ажыцьцеверыць гэтыя выходныя даныя» без сеткі, файловай сістэмы чы працюючага сервісу, то гэта ўнітарны тэст. Расглядзіце всі крайнія случаў — галоўная мета ў тым, што такія тэсты выконваюцца быстра.

    Чаго утрымвацься

    Команды марнуюць час на ўнітарныя тэсты неправільных слоёў:

    • Бібліятэкі трохцяхоў (Lodash sort, Axios headers) — вы не являецеся ўсім іх CI
    • З’яўленні/запыты да базы дадзенаў — нават варыянт у памяці SQLite ўжо належыць да інтэграцыйных тэстаў
    • Складныя сеткавыя раштры (MSW + павторныя спробы + перакананні ў заголовках) — тэрыторыя інтэграцыйных тэстаў
    • Ўсе, што трэбуе Docker, ачыненых портав чы запуску compose спачатку

    Тэст на інтуіцыю: ад’екруйце інтэрнэт. Калі тэст не працюе, гэта не ўнітарны тэст.

    Выбор фрэймворку JavaScript

    Падабейце інструмент да практыку будавання; аптымізавайце для досвяду распрацоўшчыка, а не толькі для моднасці. Адаптаванне пад нізькі настройкі лепшае, чым падбор найновейшага інструменту.

    Для большай часткі сучасных прыемакоў выбор стаў Vitest проты Jest.

    Vitest — моцны стандарт з Vite

    Ён пабудаваны на Vite, перадае настройкі і падтрымляе TypeScript і натыўны ESM. Рэжым абзірвання і выконанне зазвычай быстрэйшыя, чым у старэйшых інструментаў, а API, сэродзеўны Jest, спрыяе легкай міграцыі.

    Jest — стандарт промышленасці для багато практык React

    У Webpack, Next.js або старэйшых структурах у стылі CRA, Jest ўсеўключаючы рашэння: асерты, мокі, кантроль паверхні тэстаў, зьліквы. У вялічзіных рэпазітарыях ён моцнейшы, а ESM у яму менш зручны, чым у Vitest, але ўжо завершанасць і екосыстэма заставляют яго выграваць для багато команд.

    Mocha — модульныя структуры

    Корыстны для бэкендаў на Node, калі хочаце самі сабраць Chai + Sinon. Больш наяўных настройкаў, больш кантролю.

    Кароткі выбор

    • Праекты на Vite → Vitest
    • React з Webpack / Next / CRA → Jest
    • Node API, які выкарыстоўваюць модульную структуру → Mocha

    Практыкі (у стыле Jest/Vitest)

    Старацца пра тэсты, якія ўжывач можа зрозумець, якія ёсць дэтэрміністычныя і якія можна без проблем перэрабіць.

    1. Arrange–Act–Assert

    Заўжды адной і той жа структура:

    import { describe, it, expect } from 'vitest';
    import { add } from './math';
    
    describe('add()', () => {
      it('returns the sum of two numbers', () => {
        // Arrange
        const a = 2;
        const b = 3;
        // Act
        const result = add(a, b);
        // Assert
        expect(result).toBe(5);
      });
    });
    

    2. Назвы, якія опісваюць поведзенне

    Убудованыя элементы у стыле BDD з describe / it должны чытацца як рэчанкі:

    describe('CartService', () => {
      describe('when adding an item', () => {
        it('increases the total cart quantity by one', () => {
          // Test code...
        });
    
        it('updates the final checkout price', () => {
          // Test code...
        });
      });
    });
    

    Засоб для запуску тэста выдрукоўвае чытабельную рэчанку, якая паводзіцься пра службу, сітуацыю і апэктыўную змяну колькасці.

    3. Аднародныя фікстуры, а не розбросаныя літэралы

    const testUser = {
      name: 'Alice',
      age: 30,
    };
    it('returns the user name', () => {
      expect(getUserName(testUser)).toBe('Alice');
    });
    

    Змяніце прыкладныя даныя толькі ў аднам месцы.

    4. Паведзенне, а не рэалізацыя

    Пераканваюцца ў рэзультатах выходу, а не у тым, які прыватны функцыя выканана. Тэсты, звязаныя з рэалізацыёю, ламаюцца пад час безнэшкодных перэрабоц.

    5. Акуратна імітавацыя зовнішніх элементаў

    Стабы API/БД/сторонніх аплікацый для прыткасці і непаўнаважальнасці. Двойкі:

    • Стабы кантролююць вхідныя даны
    • Шпіёны сочаць за взаімадзеямі
    • Мокі, калі взаімадзея ёсць самай асэртывам
    • Фейкі як маленькія рабочыя заменнікі

    Стабаванне fetch:

    import { vi } from 'vitest';
    
    global.fetch = vi.fn(() =>
      Promise.resolve({
        json: () => Promise.resolve({ name: 'Alice' }),
      })
    );
    

    Не стварайце мокіў для сябе ж бізнес-логікі, як толькі не ўтрэба — чыразмокаванне пакрывае дыфекты.

    6. Крайнія кейсы і адказы

    Граніцы, null-значэння, порожнія строкі, некарэктныя аргументы. Абдзержайце мінімум/максімум/трохі больш, порожнія колекцыі, відсутныя поля, неправыя тыпы, ад’юбатныя значэння, крайнія цэлыя чысла.

    7. Незалежнасць

    Будзь-які парадак, будзь-якае паралельнае планаванне. Аднародныя змінныя фікстуры ствараюць каскады і неперапрацоўванне. Лепш выкарыстоўваць beforeEach для чыстага стану.

    8. CI на кожным PR

    Заўядзіце набор тэстаў на елементарны ранг у сістэме цяплай інтэграцыі, каб рэгрэсіі не дазволілі здзейсніць з’едыненне, а праўяжаныя тэсты не маглі ўсё пакрыць.

    Роль AI — і як застаўляюцься людзі

    Мадэлі большых языков ускорвают стварэнне шаблонных, павторных варыянтов і прыкладных тэмплейтаў. Заставляючы мадэль працаваць з чыстымі функцыямі і крэтэрыямі адпраўнення, можна стварыць шырокі набор рашэнняў, замаскаваць складныя аспекты і сінтэтычныя даныя, якія людзі працягваюць ігнараваць пад тэрміном.

    Мадэлі яшчэ не маюць архітэктурнага і доменнага суджэння. Корыстны падход: дазвольце AI стварыць вялікі спектр можлівых сцэнарыёў, а потым перагляньце кожную тэзу ў супрацоўке з рэальнымі трэбаваннямі пры з’еднанні. Вы стаеце рэдактаром „правільных“ рашэнняў; мадэль працюе быстра.

    Вашы сасавы з тэставання на елементарным рывені дапаможуць ўточніць гэта ўсё больш — спрыймайце вышэўказаныя практыкі як базовую лінію, а не як готавы спіс пераканаў.

    Стварэнне пачатковага набора без перавантажэння

    Пачніце з чыстых функцый домэна: вычыслення грошаў, перакананне ў падпярэнні, парсеры. Запішыце тэсты AAA з назвамі поведэння і спяльнымі фікстурамі. Дадзіце краявыя кейсы, пакуль матрыца “null / empty / max” не стане нудной. Ляч тады прыкладзіцеся да компонентаў UI, і толькі для поведэння prop→render, якое не патрабуе браузера.

    Калі тэст патрабуе базу дадзеных або Docker, намеравана пераказціце яго ў папку інтэграцыі. Строгае сачаванне папкі з тэстамі елементаў захоўвае кантракт, па якому цяжка-чырвонае стаўкі ўказвае на парадукс у логіцы.

    Пры выборэ фрэймворку не мяніце Jest на Vitest серэд розрабоцы новых функцый проста з меты моднай адміністрацыі. Калі вы ужо вікорыстоўвайце Vite, Vitest — гэта натуральны выбар. Калі монарэпа заснована на Jest і выкарыстоўвае стандарты Next.js, застаіцеся і інвестуйце ў прыгонкі в іншых аспектах (распад CI, адсортаванне снімакаў).

    Рытуалы адзінаковага перагляду

    Пад час перагляду PR адхарацьце тэсты, якія пераканаліваюцься ў лічбу вызоў прыватных методаў. Адхарацьце спяльныя, зменныя фікстуры між файламі. Першы чым з’еднаць код, неабходна, каб тэсты на елементарныя функціі давалі рэзультат «зелены» у CI. Перыядычна выдаліце тэсты, якія проста павтараюць поведзенне бібліятэкі для мокінгу.

    Калі вы вікорыстоўваеце AI для стварэння набораў тэстаў, запішыце чыстую функцію і крытэрыя прыйнятнасі, а потым выдаліце пераканаленні, якія маюць у сабе выдуманыя вакуфікацыі. Людзі яшчэ і так вяршаюць, што значыць «правільна»; мадэлі проста пішуць быстрэй.

    Памятка напрыканце

    Елементарныя тэсты ўтвараюць недорогую страховку, калі яны застаюцца шырокімі, ізольаванымі і сфокусаванымі на рэзультатах. Захавайце гэты нішовы падход. Дазвольце інтэграцыйным тэстам і тэстам E2E кераваць рэштой структуры, ўжо таму, каб база ніколі не стала мініяцюрным прыемным сераўерам.

    Каталог конкрэтных крайніх прыкладаў, якія можна скопіюваць

    Для чысловых API: ноль, адзін, максімальна значэнне целага, адваротныя значэнні, NaN, як гэта прыменяецца, а таксама значэнні на адзін больш за задокументаваны ліміт. Для стрэнгаў: порожній, толькі прабелы, Unicode, чрэзвычайна дугі. Для калекцый: порожняя, з адным элементам, дуплікаты, спакаяныя або зворачана спакаяныя. Для об’ектаў: відсутныя ключы, null-значэнні ў вёскапаных полях, нечаканыя дадатковыя ключы, калі ваш парсер ўскладнены.

    Запішыце іх аднойчы як прыклады, базаваныя на табліце, калі інструмент для запуску гэта падтрымляе. Такі каталог становіцца частынай культуры команды і запобiegае прагласам, якія адносуюцца толькі да “гарных” сцэнарыяў.

    Снімкі стану з абераганнем

    Снімкі стану у Jest падыходзяць для стабільнага візуальнага выхаду, але ўпадзячы для маркапаў, якія зменяюцца. Для інтэрактыўных компанентаў лепш выкарыстоваць явныя асэрцыі ўзгалі і на тэкст, за дапамогою Testing Library. Калі вы застаўляеце снімкі стану, перагледзіце разлікі як код для працы ў продакшэне — а не як шум, які трэба проста пераклікнуць.

    Паралельныя падказкі для CI

    Разбіляйце тэсты па файлах, негайна адзначайце абяроны ў першым тэсце на едыніцу, і старайцеся, каб час выканання тэста на едыніцу не перавышаў калькі хвілін. Якшча працэс CI для тэстаў на едыніцу рэгулярна перавышае гэты час, значыць у вас або занадта многі тэсты інтэграцыі, якія пазначаны як тэсты на едыніцу, або ў файле setupFiles знаходзіцца код для запуску асяроддзя, які спамошчае працэс.

    Аддзельна сачыце за канцэнтрацыяй абяронаў. Суіта тэстаў, якая становіць «зелёную» пасля двух перапрыяў, не ёсць «зелёной».