Почему вам следует писать модульные тесты

Итак, давайте поговорим о том, почему нам нужно писать модульные тесты. Основная причина написания модульных тестов — избежать внесения критических изменений в базу кода. Некоторые базы кода могут быть очень большими и содержать тысячи кодов. Из-за небольшого изменения, которое вы пытаетесь внести, вы не можете гарантировать, что вы ничего не сломаете в отдельном компоненте, который этот компонент использует. но если вы написали модульные тесты и при их запуске вы сможете увидеть, не сломано ли что-то.

И еще одна причина написания модульных тестов: это отличный способ документировать ваш код. Запуск модульного теста для компонента точно покажет, что этот компонент может делать и как он будет себя вести.

Лучше всего то, что вы можете быть полностью уверены в том, что код, который вы отправляете в рабочую среду, на 100% не поврежден.

Что вам следует протестировать

Модульный тест звучит захватывающе, не правда ли? Но чтобы извлечь из этого максимальную пользу, вам, возможно, захочется понять, что вам следует тестировать.

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

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

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

Лучше не писать модульные тесты, чем бесполезные модульные тесты.

И попытка протестировать код с его зависимостями, не заглушая их (заглушка - это что-то вроде насмешки, но в основном используется, когда мы тестируем что-то, чего не ожидаем взамен. На данный момент я также не на 100% уверен, отвечая на этот вопрос, но то, что я обычно делаю я использую самый простой вариант для выполнения своей работы.)

Как писать модульные тесты

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

Давайте возьмем простой пример того, как написать модульные тесты для функции, которая ожидает три аргумента в виде itemsArray, от даты и до даты, и вернет список записей, находящихся между ними и датами.

function filterObjectsByDateRange(arrayOfObjects, fromDate, toDate) {
  const filteredArray = arrayOfObjects.filter((object) => {
    const objectDate = new Date(object.date); 
    return objectDate >= fromDate && objectDate <= toDate;
  });

  return filteredArray;
}

Давайте посмотрим, что нам следует протестировать в этом

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

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

мы можем создать макет набора данных, вызвать функцию с поддельными датами и проверить, соответствует ли возвращаемый объект ожидаемому результату.

describe('filterObjectsByDateRange', () => {
  const testData = [
    { id: 1, date: '2023-08-15', value: 'A' },
    { id: 2, date: '2023-08-20', value: 'B' },
    { id: 3, date: '2023-08-25', value: 'C' },
  ];

  test('filters objects within the specified date range', () => {
    const fromDate = new Date('2023-08-18');
    const toDate = new Date('2023-08-24');
    const filteredData = filterObjectsByDateRange(testData, fromDate, toDate);

    expect(filteredData).toEqual([
      { id: 2, date: '2023-08-20', value: 'B' },
    ]);
  });

  test('includes objects with the same start and end dates', () => {
    const fromDate = new Date('2023-08-20');
    const toDate = new Date('2023-08-20');
    const filteredData = filterObjectsByDateRange(testData, fromDate, toDate);

    expect(filteredData).toEqual([
      { id: 2, date: '2023-08-20', value: 'B' },
    ]);
  });

  test('returns an empty array when no objects fall within the range', () => {
    const fromDate = new Date('2023-08-30');
    const toDate = new Date('2023-08-31');
    const filteredData = filterObjectsByDateRange(testData, fromDate, toDate);

    expect(filteredData).toEqual([]);
  });

  test('returns an empty array when input array is empty', () => {
    const fromDate = new Date('2023-08-15');
    const toDate = new Date('2023-08-25');
    const filteredData = filterObjectsByDateRange([], fromDate, toDate);

    expect(filteredData).toEqual([]);
  });
});

Как написать тестируемый код

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

function filterObjectsByDateRange(arrayOfObjects, fromDate, toDate) {
  const filteredArray = arrayOfObjects.filter((object) => {
    const objectDate = new Date(object.date); 
    return objectDate >= fromDate && objectDate <= toDate;
  });

  return filteredArray;
}

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

Давайте проверим несколько других методов, которые мы могли бы использовать.

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

И важно обеспечить, чтобы одна функция выполняла единственную ответственность.

И последнее, но не менее важное: вы всегда можете использовать возможности ИИ для написания модульных тестов. Хорошими вариантами являются Git Hub Co-Pilot и Chat GPT. Ключ к успеху здесь в том, что вы понимаете, что нужно протестировать, и позволяете ИИ написать за вас синтаксис.

Краткое содержание

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

  • Разделение пользовательского интерфейса и логики
  • Передача зависимостей в функцию (или внедрение зависимостей)

И обязательно протестируйте одну единицу кода.

Ваше здоровье!

Следуйте за мной в твиттере: https://twitter.com/Shuboothi