nmk

Лабораторне заняття №23 (2 години). Написання модульних та E2E тестів.

Мета

Зрозуміти важливість автоматизованого тестування у великих проектах. Написати перший модульний тест (Unit Test) за допомогою фреймворку Vitest (аналог Jest) для перевірки логіки підрахунку ціни кошика. Познайомитися з E2E тестуванням (End-to-End) за допомогою Cypress для симуляції дій користувача.

План

  1. Знайомство з пірамідою тестування (Unit, Integration, E2E).
  2. Встановлення vitest для React-додатку створеного на базі Vite.
  3. Винесення логіки calculateTotal у окрему “чисту” функцію.
  4. Написання Unit-тесту для перевірки суми товарів.
  5. Опціонально: огляд підходу до E2E тестування.

Хід роботи

Увага: На цьому етапі ви дізнаєтесь, як гарантувати, що ваш код “TechShop” не зламається (не регресує) при додаванні нових фіч іншими програмістами. Ми навчимо комп’ютер перевіряти наш код автоматично.

  1. Встановлення Vitest:
    • Відкрийте термінал у вашому проекті techshop.
    • Оскільки ми використовуємо Vite, найліпшим варіантом є його рідний тестувальник:
      npm install -D vitest
      
    • У package.json додайте команду для запуску:
      "scripts": {
        "dev": "vite",
        // ...інші команди
        "test": "vitest"
      }
      
  2. Ізоляція “Чистої” Функції (Pure Function):
    • Тестувати код, який зашитий усередину React-компонента, складно.
    • Створіть нову папку src/utils і всередині файл cartUtils.js.
    • Напишіть “чисту” функцію (яка ні від чого не залежить, тільки від вхідних параметрів):

      // src/utils/cartUtils.js
      export function calculateTotalAmount(cartArray) {
        if (!cartArray || cartArray.length === 0) return 0;
      
        return cartArray.reduce(
          (total, item) => total + item.price * item.quantity,
          0,
        );
      }
      
  3. Написання першого Unit-тесту:
    • Поруч (або в папці src/__tests__) створіть файл із суфіксом .test.js, наприклад cartUtils.test.js.
    • Напишіть тест (читається як англійський текст):

      // src/utils/cartUtils.test.js
      import { expect, test, describe } from "vitest";
      import { calculateTotalAmount } from "./cartUtils";
      
      describe("Функція підрахунку корзини (calculateTotalAmount)", () => {
        test("Повинна повертати 0 для порожнього кошика", () => {
          const emptyCart = [];
          const result = calculateTotalAmount(emptyCart);
          expect(result).toBe(0); // "Я очікую, що результат буде 0"
        });
      
        test("Повинна правильно рахувати суму товарів (враховуючи кількість)", () => {
          // 1. Arrange (Готуємо дані)
          const mockCart = [
            { id: 1, price: 100, quantity: 2 }, // Сума: 200
            { id: 2, price: 50, quantity: 1 }, // Сума: 50
          ];
      
          // 2. Act (Виконуємо дію)
          const result = calculateTotalAmount(mockCart);
      
          // 3. Assert (Перевіряємо результат)
          expect(result).toBe(250); // "Я очікую, що результат буде рівно 250"
        });
      });
      
  4. Запуск тесту:
    • Виконайте у терміналі npm run test.
    • Ви побачите зелену галочку ✓ Повинна повертати 0 та ✓ Повинна правильно рахувати.... Тепер, якщо хтось випадково зламає формулу + на - у вашому файлі cartUtils.js, цей тест засвітиться червоним екраном перш ніж помилка дійде до клієнта у продакшен!
  5. Збереження (Commit & Push):
    • Виконайте git add . та git commit -m "Add unit tests for cart calculation logic using Vitest".
    • Запушіть зміни.

Результат

Ви познайомилися зі світом QA (забезпечення якості). Це — невід’ємна частина всіх великих IT-продуктів (Senior Software Development). Ви зрозуміли концепцію TDD (Test Driven Development) і структуру “Arrange-Act-Assert”.

Контрольні питання

  1. В чому принципова різниця між Unit тестуванням (модульним) та E2E тестуванням (наприклад, через Cypress)? Що кожне з них перевіряє?
  2. Що таке “Чиста функція” (Pure Function) в JavaScript і чому її так легко протестувати у порівнянні з функцією, яка безпосередньо змінює глобальний стан або малює DOM-елементи?
  3. Що роблять функції describe та it / test у синтаксисі тестуючих бібліотек (Jest / Vitest)? Нащо вони потрібні?
  4. Розшифруйте і поясніть на прикладі схему AAA при написанні тестів: “Arrange, Act, Assert”. Де саме у вашому коді відбувається кожен з цих трьох кроків?
  5. Що таке Test Coverage (Покриття тестами) і чи обов’язково (чи взагалі можливо) виставляти вимогу до команди “100% покриття коду”? Які проблеми це може створити?