Привет, друзья! Я – Кирилл Мыльников, frontend-разработчик в ГК Юзтех. Сегодня стартует вторая часть увлекательного путешествия в мире тестирования с помощью Jest. Если вы пропустили первую часть, не беда, ссылку на нее оставлю тут. Мы начнем с краткого обзора теории и сразу перейдем к конкретным примерам. Весь код с примерами будет выкладываться на GitHub для вашего удобства.
В данной статье разберем следующие темы:
- TDD – что это?
- Практический пример использования
- Расширенные возможности Jest
TDD – что это такое?
Test Driven Development – методология разработки программного обеспечения, основанная на принципах тестирования.
Основная идея TDD – Интеграция тестирования с самых ранних этапов разработки играет ключевую роль в минимизации ошибок и повышении качества программного обеспечения. Поддерживая постоянное тестирование на всех стадиях процесса разработки, мы обеспечиваем более стабильный и надежный продукт. Давайте продолжим интеграцию тестирования на каждом этапе разработки для достижения оптимальных результатов.
Процесс TDD

Выделим с вами сразу несколько положительных сторон и укажем их в виде мемов :)
Повышение продуктивности – Благодаря тому, что ошибки выявляются на ранних этапах благодаря тестированию, время, затраченное на исправление дефектов, значительно сокращается. Это позволяет сэкономить ресурсы команды разработки и ускорить выпуск продукта на рынок.

Повышение стабильности и устойчивости – Благодаря тестированию на ранних этапах разработки возможно быстрое обнаружение и устранение ошибок, что позволяет снизить риски, связанные с внедрением нового функционала в существующие системы. Этот подход повышает надежность и стабильность программного обеспечения.

Долгосрочная поддержка кода – Обширный набор тестов упрощает процесс внесения изменений в проект, что минимизирует риски нарушения работы существующего функционала. Это способствует гибкости разработки и повышению стабильности программного обеспечения.

Разобрали тему TDD в теории, давайте приступим к практике
Практический пример использования и с чего начать?
Мы начнем разработку с написания тестов. Давайте возьмем поле email в качестве примера и определим базовые требования к нему. Далее мы составим тесты, чтобы протестировать это поле. Давайте приступим!
Пример:

На текущем этапе мы только сформулировали требования к задаче в виде тестов. Если у вас возникли вопросы или нужна дополнительная информация для формирования требований, обратитесь к заказчику для уточнения деталей. После описанных требований, давай просто напишем тесты, но обратите внимание, фича с email
у нас еще не реализована
Пример с тестом:
import { validateEmail } from "./validateEmail";
describe("validateEmail", () => {
it("should return true for valid email", () => {
expect(validateEmail("test@example.com")).toBe(true);
});
it("should return false for invalid email", () => {
expect(validateEmail("")).toBe(false);
expect(validateEmail("testexample.com")).toBe(false);
expect(validateEmail("test@example@example.com")).toBe(false);
expect(validateEmail("test@example")).toBe(false);
expect(validateEmail("test@192.168.1.1")).toBe(false);
});
it("should return true for email with dot at the end", () => {
expect(validateEmail("test@example.com.")).toBe(true);
});
it("should return true for email with plus sign", () => {
expect(validateEmail("test+example@example.com")).toBe(true);
});
it("should return true for email with special character in local part", () => {
expect(validateEmail("test!example@example.com")).toBe(true);
});
});
Пример с функцией validateEmail:
export const validateEmail = (email: string) => {};
После запуска тестов, мы видим, что они упали и это логично, потому что мы сначала написали тесты, а теперь давайте перейдем уже к функционалу.

После чего можем писать уже функционал и поэтапно запускать тесты
Пример:
export function validateEmail(email: string) {
if (!email) {
return false;
}
const emailRegex =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return emailRegex.test(email);
}
Результат:

Изменение требований (рефакторинг)
Теперь, при изменении требований, необходимо не только выводить общую ошибку "Неверный email"
, но также точно подсвечивать клиенту, что именно было введено некорректно. После изменения требований потребуется провести рефакторинг, так как после запуска тестов они упадут.
Новые требования:
- Отображать текст ошибки когда пустое поле:
"Email should not be empty."
- Отображать текст ошибки если отсутствует символ
"@"
:"Invalid email format. Please include '@' symbol."
Пример:

После рефакторинга

Тесты, которые были добавлены:
it('should return "Email should not be empty" for empty email', () => {
expect(validateEmail("")).toBe(validationEmailMessage.length);
});
it('should return "Invalid email format. Please include "@" symbol." for invalid email', () => {
expect(validateEmail("testexample.com")).toBe(
validationEmailMessage.format
);
});
Ну вот, мы посмотрели жизненный цикл TDD на примере Jest. Давайте поговорим о более продвинутых возможностях Jest, которые помогут вам улучшить тестирование вашего приложения, а именно:
- Несколько конфигов
- Shapshot тестирование
Несколько конфигов
Есть ситуации, когда нам нужно 2 разных jest конфига, например отдельный конфиг для unit-тестов и отдельный конфиг для интеграционных тестов. Соответственно можем их настраивать по-разному, хранить в разных папках, создавать разные расширения для файлов и т. д. Давайте перейдем сразу к практике, у нас есть уже один файл jest конфига, создаем второй под названием jest.integration.config и пропишем сразу настройки.
import type { Config } from "jest";
const config: Config = {
verbose: true,
preset: "ts-jest",
collectCoverage: true,
collectCoverageFrom: [
"<rootDir>/*.{js,ts}",
"!**/node_modules/**",
"!<rootDir>/*.mock*",
"!<rootDir>/*.config.*",
],
testMatch: ["<rootDir>/src/**/*.spec.ts"],
};
export default config;
Обратите внимание на testMatch, где наши интеграционные тесты будут лежать с расширением spec. Чтобы по разному запускать тесты, нужно это указать в scripts
Пишем тесты уже с расширением spec и запускаем их. Подробно можно посмотреть тут
Пример:

Snapshot тестирование – это подход к тестированию, который фиксирует вывод или состояние приложения и сравнивает его с ранее сохраненным снимком. Этот метод тестирования опциональный, используется не всегда.
Давайте сразу перейдем к практике, создадим с вами обычную функцию, которая будет создавать с вами объект.
Пример:
type User = {
name?: string;
lastName?: string;
age?: number;
phone?: string;
email?: string;
};
export const createUser = ({ name, lastName, age, phone, email }: User) => {
return {
name,
phone,
email,
age,
lastName,
};
};
Теперь давайте напишем к нему тесты и запустим
Пример:
import { createUser } from "./createUser";
describe("createUser", () => {
it("should create user with firstname and lastname", () => {
const user = createUser({ name: "Kirill", lastName: "Korobov" });
expect(user).toMatchSnapshot();
});
});
Здесь с вами создаем пользователя и когда запустим тесты, то сделается снимок нашего теста
Результат:

Теперь давайте просто в нашей функции удалим одно значение и заново запустим тесты. Я удалил поле name
и теперь снепшот-тесты падают, т. к. ожидалось это поле.
Пример:

А если вы вправду удалили это поле и оно больше не нужно, тогда нужно обновить снепшоты, в моем случае командой yarn start -u
Обновленный снепшот файл

Итак, мы с вами разобрали, что такое TDD и увидели все это на примере. Рассмотрели более продвинутые возможности Jest. Впереди нас ждет 3 часть статьи уже на примере React приложения.
Материалы:
GitHub —https://github.com/kirill0202/Jest
Jest — https://jestjs.io/
Комментарии