Вдохновение

На одном из моих курсов CS нас учили писать реализацию кода ровно столько, чтобы пройти модульные тесты. Это называется «Разработка через тестирование» (TDD), и все дело в том, чтобы убедить себя/свою команду в том, что код ведет себя так, как задумано для конкретных случаев использования. Прежде всего, вам придется сначала написать модульные тесты, а затем написать реализацию для прохождения тестов.

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


HacktoberTest — ха-ха, это каламбур…

Ежедневное участие в юнит-тестах и ​​работа с лабораториями/заданиями действительно помогло мне найти подходящие билеты, чтобы внести свой вклад во время Hacktoberfest!

Мои первые 2 PR(1-й & 2-й) скорее всего newbie level и я хотел внести свой вклад в нечто большее meaningfulчто-то, что бросило бы мне интеллектуальный вызов. Я провел хорошую неделю или около того, думая о том, что сделать дальше на страница проблем, только чтобы подчеркнуть еще больше. Мне стало ясно, что если вы пролистываете и прокручиваете страницу с проблемами только для того, чтобы найти идеальную проблему для вашего варианта использования, вы обречены … есть еще 20 000 человек, которые делают то же самое только для того, чтобы получить хабары. Таким образом, вы, вероятно, потратите больше энергии на поиск, чем на написание новой функции с нуля или сложное исправление ошибки.

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


Взлом

Проект, в котором я участвовал, был веб-приложение называется pr-одобрить-генератор который генерирует обнадеживающие сообщения для PR. Он предназначен для использования сопровождающими проектов на GitHub для поощрения их участников.

Описание изображения

Каждый раз, когда вы нажимаете на Refresh кнопку, вы получите новое сообщение, приветствующее PR и призывающее автора продолжать в том же духе. Сообщения хранятся в массиве, и приложение случайным образом выбирает одно из них для отображения. Вот функция, которая обрабатывает эту логику:

getRandomMessage() {
    const { messagesState } = state;
    const index = Math.floor(Math.random() * messagesState.length);
    let newMessage;
    let newMessagesState;
    if (messagesState.length !== 0) {
    newMessage = messagesState[index];
    newMessagesState = [
        ...messagesState.slice(0, index),
        ...messagesState.slice(index + 1),
    ];
    } else {
    newMessage = messages[index];
    newMessagesState = [
        ...messages.slice(0, index),
        ...messages.slice(index + 1),
    ];
    }
    state.messagesState = newMessagesState;
    return { newMessage, newMessagesState };
},
Войти в полноэкранный режим

Выйти из полноэкранного режима

||:—:|| Ты можешь проверить рандомайзер.js для лучшего понимания

Первый выпуск Я решил написать модульные тесты для getRandomMessage функция. Функция отвечает за выбор случайного сообщения из массива и его возврат, а также удаляет сообщение из массива, чтобы это сообщение больше не выбиралось. Если в массиве больше нет сообщений, пустой массив снова заменяется массивом сообщений и так далее. Эта функция вызывается каждый раз, когда Refresh кнопка нажата. (Также недавно в приложение была добавлена ​​новая функция, позволяющая менять эмодзи с помощью getRandomEmoji функция и работает в очень похожей логике, описанной выше. Я также поднял PR, чтобы написать тест для этой функции. здесь).

Среда модульного тестирования уже была реализована с использованием механизм поэтому я начал взламывать, настроив поставщика покрытия, чтобы явно идентифицировать covered/uncovered линий и упомянул об этом сопровождающему в Комментарии. я использовал Стамбул 🇹🇷 для этой цели.


Модульное тестирование является терапевтическим и болезненным

Я начал издеваться над messages & emojis array и назвал getRandomMessage() с издевательским массивом. В зависимости от выбранного индекса я утверждал, что возвращенное сообщение не равно новому состоянию сообщения, поскольку сообщение было удалено из массива (т. е. они должны быть уникальными).

  it("should always return unique message", () => {
    const messages = ["1", "2", "3", "4", "5"];
    const emojis = ["1", "2", "3", "4", "5"];
    const randomizer = buildRandomizer(messages, emojis);

    const { newMessage, newMessagesState } = randomizer.getRandomMessage();
    expect(newMessagesState).not.toContain(newMessage);
  });
Войти в полноэкранный режим

Выйти из полноэкранного режима

Обратите внимание, что этот тест следует AAA (Arrange-Act-Assert) шаблон. Arrange часть, где вы настраиваете только данные, которые будут работать в тесте.

const messages = ["1", "2", "3", "4", "5"];
const emojis = ["1", "2", "3", "4", "5"];
Войти в полноэкранный режим

Выйти из полноэкранного режима

Act часть, где вы бы вызвали функцию/ы, которые вы хотите протестировать.

const randomizer = buildRandomizer(messages, emojis);
const { newMessage, newMessagesState } = randomizer.getRandomMessage();
Войти в полноэкранный режим

Выйти из полноэкранного режима

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

expect(newMessagesState).not.toContain(newMessage);
Войти в полноэкранный режим

Выйти из полноэкранного режима

Имея в виду этот шаблон, я написал все файл randomizer.test.js и поднял пиар. Мой второй пиар речь шла о написании модульных тестов для файл messages.test.js убедиться в следующем;

  • Каждое сообщение должно быть уникальным независимо от используемого формата и эмодзи.
  • Дублированные сообщения не проходят проверку
  • Сообщение LGTM не пройдет проверку независимо от формата

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

it("should have unique messages regardless of the emojis", () => {
  const regex = /([a-zA-Z0-9 ])/g;
  const uniqueMessages = messages.map((message) =>
    message.match(regex).join("").toLowerCase()
  );

  expect(uniqueMessages).toEqual([...new Set(uniqueMessages)]);
  expect(uniqueMessages.length).toBe(messages.length);
});
Войти в полноэкранный режим

Выйти из полноэкранного режима

О, и я также убедился LGTM не приветствуется :Р

it("should never contain the message LGTM", () => {
  const lgtmMessages = messages.filter(
    (message) => message.toLowerCase() === "lgtm"
  );
  expect(lgtmMessages).toEqual([]);
});
Войти в полноэкранный режим

Выйти из полноэкранного режима

Теперь отчет о покрытии с гордостью показывал покрытые линии зеленым цветом со 100%! Это обеспечивает ценность, поскольку отчет является визуальной индикацией и документированием жизнеспособности тестов. Это дало мне чувство выполненного долга, и я нашел это терапевтическим, чтобы увидеть, что это работает так, как было задумано.


Проблемы с git

Однако во время моего второго PR у меня были проблемы с git branches. Изначально, когда я писал модульные тесты для randomizer.test.js файл, у меня была ветка под названием tests-for-randomizer для реализации необходимых тестов для этого конкретного файла. После того, как я реализовал свою работу в этой ветке, для своего второго PR я создал новую ветку под названием tests-for-messages реализовать тесты на messages.test.js файл с помощью команды git checkout -b tests-for-messages. Очевидно, что вся работа, которую я выполнил для randomizer.test.js пришла вместе с новой веткой messages.test.js.

надо бы сначала обновить master ветка и в текущей ветке tests-for-messages перебазировать в мастер с git rebase master -i (-i для интерактива), чтобы удалить коммиты, которые не были связаны с messages.test.js файл. Проблема заключалась в том, что я практиковал rebase только самостоятельно, и мне было страшно делать это в проекте с открытым исходным кодом. Я боялся испортить проект и потерять работу. я спросил некоторые помощь от сопровождающего и он управляемый мне хорошо через процесс. Итак, в заключение, чтобы решить эту проблему, мне пришлось перебазировать ветку tests-for-messages к master который удалил коммиты, которые не были связаны с messages.test.js файл и сделал принудительное нажатие на удаленную ветку tests-for-messages с git push -f origin tests-for-messages. Сопровождающий был доволен результатом и объединил PR, и я был уверен, что


Боль в модульном тестировании

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


Вывод

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