Если вы заказываете разработку сервиса или приложения для своего бизнеса, наверняка столкнетесь с юнит-тестами, поэтому для начала разберемся...
Что это такое юнит-тесты
Юнит-тесты — это вид тестирования разработанных программ, при котором проверяются отдельные элементы процессов, кода, модулей.
Например, у вас есть приложение для формирования заказа доставки готовой еды. В этом случае unit-тест будет подразумевать отдельную проверку модуля для создания меню, раздела выбора способа доставки, а также способов оплаты.
В целом подобное тестирование относят к низкоуровневым тестам. Они предназначены для проверок отдельных элементов создаваемого кода. В отличие от высокоуровневых тестов, здесь уделяется внимание не потребительским свойствам программы, а правильной работе функций.
Простыми словами, юнит-тест — это проверка созданной программы частями.
Зачем нужны юнит-тесты
В первую очередь низкоуровневое тестирование позволяет избежать накопления ошибок, а значит снижает риски возникновения серьезных сбоев в работе программы. Юнит-тесты позволяют проверить отдельные компоненты, чтобы не случилось ситуации когда после сборки всех модулей приложения оно оказывается работающим нестабильно.
Перечислим основные задачи:
- Выявление и устранение ошибок в начале разработки. Позволяет уменьшить затраты в дальнейшем.
- Гарантия работоспособности кода. Успешно проведенный тест позволяет разработчикам говорить о качестве написанного программного обеспечения.
- Простая и быстрая корректировка продукта. Достигается за счет лучшего понимания разработчиками структуры кода.
- Повторное использование кода. Юнит-тесты применяются при переносе части кода в другое приложение.
- Применение в проектной документации. Это дает возможность сторонним специалистам быстрее разобраться в проекте.
Если свести все задачи к одному знаменателю, выйдет, что все они дают возможность снизить затраты на разработку, уменьшить риски грубых ошибок при разработке.
Пример юнит-теста
Разберем пример теста. Он начинается с обязательной текстовой строки или нескольких строк, где указывается, что конкретно проверяется
Дальше прописываем функцию, которая будет проверяться. Этот элемент должен «заваливать» функцию. Получается своеобразная тестовая заглушка.
Дальше указываем несколько наборов данных для тестирования. В первом наборе указываются данные с погрешностью. Здесь применен тестовый макрос BOOST_REQUIRE. По идее, программа должна при запуске макроса показывать истинность утверждения и выдавать результат true. Во втором наборе применяются неравные числа и макрос BOOST_REQUIRE_EQUAL. Результатом запуска должен стать ответ: false. Это означает, что утверждение неверно.
Теперь нужно проверить правильность созданного теста. Для этого добавляем в проект опцию log_level=test_suite. Она определяет порядок запуска тестов. В консоли должен появиться вот такой список:
После этого можно проверить уже имеющуюся функцию. Например, такую:
На скриншоте можно увидеть результат, который должен оказаться в консоли. Это расшифровывается как проведение двух тестов, не обнаруживших ошибок.
Показанный пример юнит-теста можно назвать простейшим. Здесь всего одна функция и нет никакого большого разброса в проверяемых данных.
Особенности тестирования
Юнит-тесты могут эффективно работать в связке с высокоуровневым тестированием. И зачастую на практике снижают затраты на обширные тесты. Например, проверка отдельных частей кода в процессе теста выявила ошибку, ее устранение уменьшит число ошибок на высоком уровне и снизит затраты ресурсов на их выявление.
Все особенности юнит-проверок можно свести к следующим моментам.
- Непонятный код. Иногда возникают ситуации, когда новому разработчику непонятно, как работает код. Тестирование отдельного элемента дает возможность разобраться в запускаемых процессах.
- Частые изменения. Тесты упрощают работу по проверке новых участков программы, это важно в случаях, когда в нее вносятся правки.
- Проверки при обновлениях. Если в программе появляются новые функции, юнит-тестирование позволит проверить совместимость отдельных элементов кода.
Только не нужно подменять юнит-тестами масштабное тестирование на высоких уровнях. Все виды тестов должны использоваться для достижения максимальной работоспособности программного обеспечения.
Преимущества и недостатки юнит-тестов
Теперь рассмотрим чем могут быть полезны юнит-тесты, а также посмотрим на объективные недостатки.
Начнем с плюсов:
- Простота. Если говорить о тестировании, проверить отдельный кусок кода и найти там ошибки гораздо проще, чем изучать все приложение. Это дает возможность работать с программой даже начинающим тестировщикам.
- Параллельная разработка. Появляется возможность работать сразу над несколькими функциями приложения. К примеру, вы можете одновременно настраивать правильность вывода данных по результатам вычисления, а также создавать красивую анимацию в приложении.
- Информативность. Грамотно проведенный тест дает возможность разобраться в особенностях работы приложения. Это особенно ценно, когда меняется разработчик или вся команда.
- Повторное применение. Если создать тест один раз, его можно будет повторять неоднократно по мере необходимости. В крайнем случае, вам нужно будет только немного дополнить уже имеющийся тест.
- Документация проекта. Зачастую тестирование используют для быстрого написания документов по созданному приложению, это упрощает подготовку проекта к передаче заказчику.
Есть и минусы.
- Нет гарантий выявления всех ошибок. Так как тестирование происходит отдельными модулями, вы не сможете увидеть, как все они работают в комплексе.
- Применение к изолированным модулям. Для каждого отдельного модуля придется создавать свой тест.
- Нет возможности проверить взаимодействие модулей. Если программа состоит из большого числа подпрограмм, невозможно при проверке каждого элемента кода увидеть, как они будут взаимодействовать между собой.
В целом преимущества перевешивают недостатки: просто о минусах нужно помнить, чтобы не возникало лишних проблем в процессе разработки.
Процесс юнит-тестирования
Первое, что нужно помнить — как только вы написали участок кода, сразу делайте под него тест. Это позволит гарантированно покрыть тестированием все элементы приложения.
Для юнит-тестирования используются специальные фреймворки. Они имитируют работу приложения в рабочей среде. Также они указывают на ошибки возникшие в процессе запуска. Для каждого языка программирования существуют свои фреймворки, причем для самых популярных языков их несколько.
Обычно процесс пошагово выглядит так:
- Выбираем код для тестирования. Здесь необходимо учитывать, что сам по себе код не должен быть большим по объему. В идеале нужно проверять одну функцию. Это упростит создание теста и позволит увеличить эффективность процесса.
- Решаем, как будем делать тест. Есть два варианта: внутри приложения или вынося код в отдельный файл. Второй вариант считается идеальным решением. Первый способ с тестированием внутри приложения применяется когда нужно проверить взаимодействие с другими элементами кода, например, правильность прописанных классов.
- Прописываем тест. Для этого указываем в коде проверяемые данные. Например, это могут быть определенные параметры id, которых не может быть на практике.
- Запускаем тест. Для этого вам потребуется фреймворк. В результате у нас будет список результатов.
- Интерпретация результатов. Определяем насколько корректно сработал код. Если в тесте использовались неправильные данные, а у нас результат положительный, то это будет ошибкой.
На практике в большей части языков программирования все эти процессы производятся в полуавтоматическом режиме.
Рекомендации
Чтобы эффективно провести юнит-тестирование, нужно соблюсти ряд правил.
- Простые тесты. Не нужно гнаться за сложностью, лучше написать тест, который проверит одну функцию, чем сделать сложную проверку и потом думать, почему получен такой результат. Обычно чем проще выполняемая проверка, тем она более достоверна.
- Проверка ошибок. Обязательно нужно смотреть, что будет если в программу ввести неправильные данные. В идеале стоит сразу делать тесты на все возможные варианты данных. Если у нас используется числовой диапазон, в тесте должен быть допустимый диапазон, а также два варианта с уменьшением и превышением данных. Например, программа должна работать в диапазоне от 1988 по 2001 годы. Обязательно проверьте, как будет отрабатывать функция при вводе меньшего числа или большего.
- Обязательно покрывайте тестами все циклы. Как правило, ошибки в циклах могут сломать все приложение.
- Следите за достаточным покрытием кода тестированием. Не нужно стремиться к полной проверке всех функций, это возможно только на совсем маленьких проектах. Оптимально если вы будете тестировать 70–80% функций.
- Оптимизация скорости. Следите, чтобы все тесты выполнялись быстро. В случае когда проверка проходит 10–20 минут, разработчики просто ее отключат.
- Стабильность. Юнит-тесты должны быть надежными и показывать стабильный результат без дополнительных настроек.
Отдельно стоит упомянуть необходимость выделять конкретного специалиста для тестирования. Время программистов стоит дорого, поэтому для сложных проектов лучше нанять тестировщика. Это позволит выполнять проверку кода не отвлекая программистов от основной деятельности. Так убивается сразу два зайца: с одной стороны достигается высокий процент покрытия кода тестированием, с другой стороны ускоряется процесс разработки.
Когда можно обойтись без юнит-тестирования
Единственный случай, когда можно обойтись без unit-тестов — это случай, когда «проект нужно было сдать вчера, а он только дописывается».
То есть, в случае когда команды разработки совсем нет времени для запуска проверок, и они в целом уверены в том, что программа отрабатывает нормально, можно обойтись без тестирования. Обычно это происходит в случае с простыми программами: например, если нужно сделать простенький калькулятор для сайта, его можно не тестировать.
В целом отказ от юнит-тестов приводит к росту ошибок в приложении. Причем, чем дольше вы будете отказываться от тестирования, тем сложнее будет потом разобраться в том, из-за чего все-таки возникли сложности.
Коротко о главном
- Юнит-тесты дают возможность проверки отдельных частей программы.
- При запуске обновлений, подобное тестирование даст понимание, как работают новые элементы кода.
- Unit-тестирование позволяет разобраться в сложном и непонятном коде.
- К основным преимуществам можно отнести простоту проведения, а также возможность параллельной разработки.
- Есть риски пропустить ошибку, которая возникает при совместной работе отдельных частей программы.
- Покрытие программы тестами должно превышать 60 %, но не нужно стремиться к полной проверке.
- Рекомендуется выделять для этой работы конкретного специалиста.
Комментарии