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

Вот скажи, оно мне надо? Это лишняя работа!

При написании кода неизбежно будут ошибки. И неважно насколько вы крутой разработчик и какую должность занимаете: Junior, Middle или Senior. Опытного программиста отличает не количество ошибок, а умение их быстро находить и исправлять. При создании какого-либо приложения, всегда прописываются методы и функции. Unit-тестирование создано для того, чтобы модулями проверять каждую из таких функций или методов. В итоге, хороший код — тот, который весь покрыт unit-тестами. Это значительно сокращает время на поиск ошибок, а значит и влияет на скорость разработки в положительную сторону.

Кстати, это будет полезно и при написании pet-проектов для собесов, что само по себе очень крутая практика. Допустим, мы пишем функцию, которая считает сумму всех бутылок в холодильнике с колой. Их должно быть 240 в одном холодильнике и 240 в другом. Всего 480 бутылок с чудо-жижей из каналов в Half-Life 2. Unit-тест, который я напишу для этой функции, должен проверить, а правильно ли выполнена функция, и получу ли я ожидаемый ответ — 480. Если результат функции равен тому, что заложен в тесте — ура, всё работает корректно. Можно открыть холодос и бахнуть бутылку эликсира за это.

И теперь представим, что нам нужно посчитать не сумму бутылок колы в двух холодильниках, а целый магазин товаров для гиков, где стоит этот холодос. Есть полки с модельками, с мерчом, и каждый из них ещё разбит по вселенным. И тут можно понять, что проверять каждый из них вручную, просто подряд просматривая каждую из полок — дело вот вообще неблагодарное. Проще сразу написать unit-тесты, которые проверят, а правильно ли посчитано количество фигурок Примархов из Вахи или плащей Бэтмена.

Ну и как я это сделаю?

Собственно, а как создать то эти самые Unit-тесты? Существует множество библиотек для проведения unit-тестов на Java. Вот лишь некоторые из наиболее популярных:

  • JUnit — наиболее распространенная библиотека для unit-тестирования. Она предоставляет аннотации, методы и классы для тестирования кода.

  • TestNG — другая популярная библиотека для тестирования Java-кода. Она обладает расширенными возможностями для тестирования, такими как группировка тестов и тестовые параметры.

  • Mockito — популярная библиотека макетирования объектов для Java. Она позволяет создавать фиктивные и макетные объекты для тестирования кода.

  • PowerMock — расширенная библиотека макетирования объектов для Java. Она позволяет создавать макеты статических методов, конструкторов и т. д.

  • AssertJ — библиотека, позволяющая писать более читабельные и удобные тесты, чем стандартные Assert-методы. Это только некоторые из множества библиотек, доступных для проведения unit-тестов на Java.

Рассмотрим три самые популярные из этого списка: JUnit, Mockito и TestNG. Они используются чаще всего, как подсказывает практика, и наиболее удобны для написания тестов, т.к. понятны как новичкам, так и более прошаренным за код дедам индустрии.

JUnit

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

JUnit — это библиотека для тестирования программного обеспечения (unit-тестирования) на языке Java. Она позволяет создавать и выполнять тесты, а также проверять результаты работы программы.

JUnit предоставляет собой набор аннотаций (@Test, @Before, @After и т.д.), которые помогают определить тестовые методы и методы инициализации и завершения тестов. JUnit также обеспечивает удобный способ создания тестовых наборов (test suites), которые дают возможность объединять несколько тестовых классов или методов в единый тест. Ну и используется JUnit во всех языках, что поддерживают объектно-ориентированный подход, от Java до Python'а.

Mockito

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

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

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

TestNG

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

  • Поддержка аннотаций: TestNG предоставляет набор аннотаций для создания тестовых сценариев, таких как @Test (для обозначения тестового метода), @BeforeSuite (для перед выполнением всех тестов) и @AfterMethod (для очистки ресурсов после каждого выполняемого метода).

  • Гибкие конфигурационные параметры: TestNG позволяет конфигурировать тестовый запуск с помощью xml-файлов, что очень удобно при работе с большим числом тестов.

  • Группировка тестов: TestNG позволяет группировать тесты по своим функциональным особенностям и запускать их отдельно от других групп.

  • Поддержка параллельного выполнения: TestNG позволяет запускать тесты параллельно, что ускоряет время их выполнения.

  • Генерация отчетов: TestNG предоставляет мощный механизм генерации отчетов, что помогает в легкой и быстрой отладке найденных ошибок в программах.

  • Бесплатный и открытый исходный код: TestNG разработан на языке Java и распространяется под лицензией Apache, что даёт возможность использовать его бесплатно и изменять исходный код.

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

Ну и что в итоге то?

В конце концов мы приходим к тому, что unit-тестирование и правда мастхэф для разработчика любого абсолютно уровня, потому как от этого зависит и вся разработка в целом, в общем-то.

То есть, проверяя свой код, вы закрываете сразу несколько проблем:

  • исключаете или минимизируете количество ошибок в том, что написали;

  • учитесь проверять сделанную работу, что всегда важно;

  • передаёте более качественный “продукт” своим коллегам;

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

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

Если вы нашли этот материал интересным и полезным для себя будем рады вашим реакциям!

Комментарии (5)


  1. scome
    04.12.2024 06:40

    В итоге, хороший код — тот, который весь покрыт unit-тестами.

    Сильное заявление. Проверять я его, конечно, не буду


    1. DasMeister
      04.12.2024 06:40

      Это же почти дословная цитата, цитаты из вступления к книге "Чистый код", Мартина. Удивительно, что тимлид не успел проверить это весьма обыденное заявление.


      1. scome
        04.12.2024 06:40

        Рад за ваши столь доскональные знания такого значимого труда.

        В продолжение могу предложить изучить труд Хорикова «Принципы юнит тестирования» - не менее значимая книга, чем творения дядюшки Боба


    1. Qwertovsky
      04.12.2024 06:40

      Я проверял это на себе.

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

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

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

      При рефакторинге я удалил все юнит-тесты и переключился на интеграционные. Теперь все приложение можно рефакторить сколько угодно. И стек интеграционных тестов и самого приложения можно менять независимо. Лишь бы основной интерфейс оставался рабочим.

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


      1. qeeveex
        04.12.2024 06:40

        Вы сейчас описали признак проблем в архитектуре приложения.

        Мы работаем по аджайлу и у нас легко и быстро покрывается код unit тестами. Весь код делится на отдельные модули по SOLID и DDD.

        А потому что сами тесты переставали соответствовать новой логике.

        Тесты тоже нужно сопровождать и именно из-за этого они должны быть максимально простыми.