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

Три вопроса:

  1. Когда начать?
  2. Это только о тестировании кода?
  3. Имеют ли модульные тесты другие преимущества?

В этой статье мы рассмотрим различные типы тестов, напишем примеры модульного тестирования (базового и расширенного), мок-сервиса, отчета о покрытии и того, какие преимущества модульное тестирование дает командам разработчиков.

Я буду использовать Jest, платформу для тестирования JavaScript.

Различные виды тестирования

Я написал об этом статью, это хорошая отправная точка для понимания различных типов тестирования.

На диаграмме выше вы видите, что модульные тесты составляют большую основу набора тестов вашего приложения. Как правило, они небольшие, их много, и выполняются они автоматически.

Давайте быстро пробежимся по разным типам тестов (основным блокам). Иногда; грань между ними довольно тонкая.

Модульные тесты

Модульные тесты проверяют только одну часть реализации: «модуль».

Никаких зависимостей/интеграций и ничего специфичного для фреймворка. Они похожи на метод, возвращающий ссылку на определенном языке.

Сервисные (интеграционные) тесты

В какой-то момент вы захотите, чтобы код взаимодействовал с базой данных, файловой системой или другим модулем внутри/вне вашего приложения. Эта часть реализации должна быть проверена интеграционными тестами.

Как правило, они имеют более сложную настройку, которая включает в себя подготовку сред тестирования, инициализацию зависимостей и т. д.

UI (функциональные/сквозные) тесты

Модульные тесты и интеграционные тесты дают вам уверенность в том, что приложение работает. Тесты пользовательского интерфейса (функциональные/сквозные) рассматривают приложение с точки зрения пользователя и проверяют, работает ли система должным образом.

Почему вы должны беспокоиться о написании модульных тестов?

Задайте этот вопрос разработчикам: «Написали ли они тесты для своего приложения».

Типичный ответ будет;

  1. У нас не было на них времени.
  2. Нам они не нужны, я знаю, что это работает.

Модульные тесты — это не только тестирование. Они помогают вам и другими способами, поэтому разработчики могут:

  1. Уверенность в коде. Когда вы в последний раз вносили изменения в код, сборка завершалась со сбоем и половина вашего приложения перестала работать? Моя была на прошлой неделе. Но это все еще нормально. Настоящая проблема заключается в том, что когда сборка выполняется успешно, изменение развертывается, и ваше приложение начинает работать нестабильно.
    Когда это происходит, вы начинаете терять уверенность в коде и в конечном итоге просто молитесь о том, чтобы приложение заработало. Модульные тесты помогут вам быстрее обнаружить проблемы и обрести уверенность.
  2. Помочь вам принимать лучшие архитектурные решения:изменяется код, но некоторые решения о платформе, модулях, структуре и т. д. необходимо принимать на ранних стадиях проекта.
    Когда вы начните думать о модульном тестировании с самого начала, это поможет вам лучше структурировать код и добиться правильного разделения задач. У вас не будет соблазна возложить несколько обязанностей на отдельные блоки кода, поскольку это было бы кошмаром для модульный тест.
  3. Определите функциональные возможности до написания кода: вы пишете сигнатуру метода и сразу же начинаете ее реализовывать. О, но что должно произойти, если параметр имеет значение null? Что делать, если его значение выходит за пределы ожидаемого диапазона или содержит слишком много символов? Выбрасываете ли вы исключение или возвращаете null?
    Модульные тесты помогут вам обнаружить все эти случаи. Посмотрите еще раз на вопросы, и вы точно обнаружите, что именно определяет ваши модульные тесты.
    Я уверен, что написание модульных тестов дает гораздо больше преимуществ. Те, что я выучил трудным путем.

Пример: напишите свой первый модульный тест JavaScript

Мы начнем с Jest, это фреймворк для тестирования JavaScript. Это инструмент, который обеспечивает автоматическое модульное тестирование, обеспечивает покрытие кода и позволяет легко имитировать объекты.

У Jest также есть расширение для Visual Studio Code, доступное здесь.
Существуют и другие фреймворки, вы можете ознакомиться с ними в этой статье.

  1. Запустите эту команду — npm i jest --save-dev
  2. Начните с этого метода getAboutUsLink в качестве реализации для тестирования:
export function getAboutUsLink(language){
  switch (language.toLowerCase()){
    case englishCode.toLowerCase():
      return '/about-us';
    case spanishCode.toLowerCase():
      return '/acerca-de';
  }
  return '';
}

3.

const englishCode = "en-US";
const spanishCode = "es-ES";
function getAboutUsLink(language){
switch (language.toLowerCase()){
case englishCode.toLowerCase():
return '/about-us';
case spanishCode.toLowerCase():
return '/acerca-de';
}
return '';
}
module.exports = getAboutUsLink;

4. Поместите это в файл index.js.

Мы можем писать тесты в одном файле, но хорошей практикой является выделение модульных тестов в отдельный файл.
Общие шаблоны именования включают {filename}.test.js и {filename}.spec.js. Я использовал первый, index.test.js:

const getAboutUsLink = require("./index");
test("Returns about-us for english language", () => {
    expect(getAboutUsLink("en-US")).toBe("/about-us");
});

5. Во-первых, нам нужно импортировать функцию, которую мы хотим протестировать. Каждый тест определяется как вызов функции test. Первый параметр — это имя теста для справки. Другая — это стрелочная функция, в которой мы вызываем функцию, которую хотим протестировать, и указываем ожидаемый результат.

6. Здесь мы вызываем функцию getAboutUsLink с en-US в качестве языкового параметра. Мы ожидаем, что результат будет /about-us.
Теперь мы можем глобально установить Jest CLI и запустить тест:

npm i jest-cli -g
jest

7. Если вы видите ошибку, связанную с конфигурацией, убедитесь, что у вас есть файл package.json. Если нет, создайте его, используя npm init.
Вы должны увидеть что-то вроде этого:

PASS  ./index.test.js
  √ Returns about-us for english language (4ms)
  console.log index.js:15
    /about-us
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.389s

Отличная работа.

Это был первый простой модульный тест JavaScript от начала до конца. Если вы установили расширение Visual Studio Code, оно автоматически запустит тесты после сохранения файла. Давайте попробуем, расширив тест этой строкой:

expect(getAboutUsLink("cs-CZ")).toBe("/o-nas");

Как только вы сохраните файл, Jest сообщит вам, что тест не прошел. Это поможет вам выявить потенциальные проблемы еще до внесения изменений.

Пример: тестирование расширенной функциональности и фиктивные сервисы

  1. На самом деле коды языков для метода getAboutUsLink не будут константами в одном и том же файле. Их значения обычно используются во всем проекте, поэтому они должны быть определены в собственном модуле и импортированы во все функции, которые их используют.
import { englishCode, spanishCode } from './LanguageCodes'

2. Таким же образом можно импортировать эти константы в тест. Но ситуация усложнится, если вы будете работать с объектами, а не с простыми константами.

См. этот метод:

import { UserStore } from './UserStore'
function getUserDisplayName(){
  const user = UserStore.getUser(userId);
  return `${user.LastName}, ${user.FirstName}`;
}

Этот метод использует импортированные UserStore:

class User {
    getUser(userId){
        // logic to get data from a database
    }
    setUser(user){
        // logic to store data in a database
    }
}
let UserStore = new User();
export { UserStore }

3. Чтобы правильно протестировать этот метод, нам нужно имитировать UserStore. Макет — это замена оригинального объекта. Это позволяет нам отделить зависимости и реальные данные от реализации тестируемого метода так же, как манекены помогают при краш-тестах автомобилей, а не реальных людей.

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

Пример: имитация службы

  1. Чтобы имитировать объекты, вы можете либо предоставить функцию имитации, либо вручную имитировать.
  2. Мы сосредоточимся на последнем, поскольку у меня есть простой и понятный вариант использования. Но не стесняйтесь проверить другие возможности насмешек, которые предоставляет Jest.
  3. Простой случай:
jest.mock('./UserStore', () => ({
    UserStore: ({
        getUser: jest.fn().mockImplementation(arg => ({
            FirstName: 'Ondrej',
            LastName: 'Polesny'
        })),
        setUser: jest.fn()
    })
}));

4. Во-первых, нам нужно указать, что мы мокаем — модуль ./UserStore. Далее нам нужно вернуть макет, содержащий все экспортированные объекты из этого модуля.

5. В этом примере это только объект User с именем UserStore и функцией getUser. Но с реальными реализациями макет может быть намного длиннее. Любые функции, которые разработчикам на самом деле не нужны в рамках модульного тестирования, можно легко высмеять с помощью jest.fn().

6. Модульный тест для функции getUserDisplayName похож на тот, который мы создали ранее:

test("Returns display name", () => {
    expect(getUserDisplayName(1)).toBe("Polesny, Ondrej");
})

7. Как только я сохраняю файл, Jest сообщает, что у вас есть 2 пройденных теста. Если вы выполняете тесты вручную, сделайте это сейчас и убедитесь, что вы видите тот же результат.

Пример: отчет о покрытии кода

  1. Теперь, когда мы знаем, как тестировать код JavaScript, полезно покрыть как можно больше кода тестами. И это трудно сделать. Мы хотим, чтобы наши задачи выполнялись, а модульные тесты обычно приводят к нежелательной рабочей нагрузке, которую мы склонны упускать из виду.
  2. Покрытие кода — это инструмент, который помогает нам бороться с этим. Покрытие кода покажет вам, насколько большая часть вашего кода покрыта модульными тестами.
  3. Возьмем, к примеру, модульный тест, проверяющий функцию getAboutUsLink:
test("Returns about-us for english language", () => {
   expect(getAboutUsLink("en-US")).toBe("/about-us");
});

4. Он проверяет английскую ссылку, но испанская версия остается непроверенной. Покрытие кода составляет 50%. Другой модульный тест тщательно проверяет функцию getDisplayName, и ее покрытие кода составляет 100%. Вместе общее покрытие кода составляет 67%. У нас было 3 варианта использования для тестирования, но наши тесты охватывают только 2 из них.

5. Чтобы просмотреть отчет о покрытии кода, введите в терминал следующую команду:

jest --coverage

6. Или; если вы используете Visual Studio Code с расширением Jest, вы можете запустить команду (CTRL+SHIFT+P) Jest: переключить наложение покрытия. Он покажет вам прямо в реализации, какие строки кода не покрыты тестами.

7. Запустив проверку покрытия, Jest также создаст отчет в формате HTML. Найдите его в папке проекта под coverage/lcov-report/index.html.

Теперь вы должны стремиться к 100% охвату кода, верно? :-)

Вывод

В этой статье мы узнали, как начать модульное тестирование в JavaScript. Хотя приятно иметь в отчете 100% покрытие кода, на самом деле не всегда возможно (значительно) достичь этого.

Цель состоит в том, чтобы позволить модульным тестам помочь вам поддерживать ваш код и убедиться, что он всегда работает так, как задумано.

Они позволяют:

  1. Четко определите требования к реализации.
  2. Лучше проектируйте свой код и разделяйте задачи.
  3. Узнайте о проблемах, которые могут возникнуть с вашими новыми коммитами.
  4. Дайте вам уверенность, что ваш код работает.

Статьи по Теме

Перейдите к следующим местам (ссылкам), чтобы прочитать больше статей,

  1. "Разработка программного обеспечения"
  2. Все, что связано с тестированием ПО
  3. Машинное обучение, искусственный интеллект и Python
  4. Все, что связано с технологиями и потреблением электроники
  5. «Политика и соц.
  6. Качества, которые делают нас людьми
  7. И узнайте больше об издателе

О писателе:

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

Посетите его домашнюю страницу Medium, чтобы узнать больше от него.