Как сделать тесты в java

Обновлено: 05.07.2024

English version of this article you can find here.

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

В этой статье я опишу библиотеку JUnit 4, которая во многом упрощает и автоматизирует процесс написания тестов.

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

Теперь напишем Unit тесты. Для этого создадим класс с некоторым количеством тестовых методов. Естественно, класс может содержать и обычные вспомогательные методы. Чтобы runner тестов мог определить, кто есть кто, тестовые методы необходимо помечать аннтоацией @Test.

У аннотации могут быть проставлены такие параметры:

  • expected - указываем какое исключение будет сгенерировано методом (см. пример ниже);
  • timeout - через какое время в милисекундах прекратить выполнение теста и засчитать его как неуспешный.

Если вы хотите указать, что определенный тест необхдимо пропустить, то пометьте его аннотацией @Ignore. Хотя можно просто удалить аннотацию @Test.

Бывает такое, что для выполнения каждого тестового сценария вам необходим некоторый контекст, например, заранее созданные экземпляры классов. А после выполнения нужно освободить зарезервированные ресурсы. В этом случае вам понадобятся аннтоации @Before и @After. Метод, помеченный @Before будет выполняться перед каждым тестовым случаем, а метод, помеченный @After - после каждого тестового случая.

Если же инициализацию и освобождение ресурсов нужно сделать всего один раз - соответственно до и после всех тестов - то используйте пару аннотаций @BeforeClass и @AfterClass.

А вот и сам тестовый класс с несколькими тестовыми сценариями:

Метод calls тестирует правильность счетчика вызовов. Метод factorial проверяет правильность вычисления факториала для некоторых стандартных значений. Метод factorialNegative проверяет, что для отрицательных значений факотриала будет брошен IllegalArgumentException. Метод todo будет проигнорирован. Попробуйте убрать аннотацию @Ignore, когда будете экспериментировать с кодом.

Метод assertTrue проверяет, является ли результат выражения верным. Некоторые другие методы, которые могут пригодиться:

  • assertEquals - ожидаемый результат и полученный результат совпадают;
  • assertNull - результатом выражения есть null;
  • assertNotNull - результат выражения отличен от null;
  • assertSame - ожидаемый и полученный объекты это один и тот же объект.
  • fail - метод генерирует исключение AssertionError - добавляем туда, куда не должен дойти ход выполнения программы.

В нашем современном мире IDE умеют находить и просто запускать тесты в проекте. Но что делать, если вы хотите запустить их вручную с помощью программного кода. Для этого можно воспользоваться Runner'ом. Бывают текстовый - junit.textui.TestRunner, графические версии - junit.swingui.TestRunner, junit.awtui.TestRunner.

Но чуть более современный метод - это использование класса JUnitCore. Добавьте следующий метод main в класс MathFuncTest:

И результат выполнения:

В более ранних версиях JUnit для написания тестового класса нужно было создать наследника junit.framework.TestCase. Затем необходимо было определить конструктор, принимающий в качестве параметра String - название метода - и передать его родительскому классу. Каждый тестовый метод обязан был начинаться с префикса test. Для инициализации и освобождения ресурсов использовались методы setUp и tearDown. Короче ужас. Ну а сейчас все просто, да.

Вот и все на сегодня. Уверен, JUnit Framework во многом поможет вам. Комментарии и вопросы по поводу статьи приветствуются.

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

Создадим пустой maven проект:

> mvn archetype : generate - DgroupId = ru .easyjava .junit - DartifactId = base - Dversion = 1 - DinteractiveMode = false

И добавим в него JUnit:

Зависимость добавлена с test , что говорит maven, что она требуется только при сборке и исполнении тестов.

Поскольку я обещал почти настоящий пример, придётся написать хоть сколько-то полезный класс. Пускай это будем набор утилит для работы со строками:

  • Разделение строки на подстроки
  • Слияние строк из массива
  • Проверка строк на пустоту
  • Преобразование в число и обратно

Тесты в JUnit располагаются в отдельных классах, методы которых, имеющие аннотацию @Test , и возвращающие void , и есть сами тесты. Имя класса может быть в принципе любое, но рекомендуется придерживаться шаблона ИмяТестируемогоКласса Test , так как это упрощает чтение кода. К тому же обычно средства автоматического запуска тестов, такие как плагин maven maven - surefire - plugin предполагают, что классы с юнит-тестами оканчиваются на * Test

Maven традиционно располагает тесты в каталоге src / test , в то время как основной исходный код располагается в src / main . Разумеется это всего лишь договорённость, используемая в maven по умолчанию, и тесты и код можно располагать любым удобным образом.

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

Первый юнит-тест

Все юнит-тесты пишутся по единому шаблону: создаются входные данные, создаются эталонные данные (expected), вызывается тестируемый код и
результат его работы(actual) сравнивается с эталонными данными. JUnit предоставляет несколько assert * функций, выполняюших сравнение.

В первом юнит-тесте строка

и есть входные данные, которые мы отдаём в проверяемую функцию.

Эталонные данные определены в следующей строке:

Вызываем проверяемый код и сохраняем результат его работы:

Наконец самая главная часть теста, проверка:

Разработчики обычно пишут юнит-тесты только для предусмотренных разработчиком/архитектором/документацией/etc вариантов поведения функции. Для
StringUtils . fromDouble ( ) документация указывает что функция должна преобразовать цисло с плавающей запятой в строку.
Юнит-тест этой функции покрывает только описанный функционал. Цель юнит-тестирования — убедиться, что функция работает правильно, а не искать условия,
в которых она работает неправильно.

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

А самый главный бонус юнит-тестирования, это фиксация поведения кода. Вы знаете, прямо сейчас, что функция ведёт себя определённым образом. И код, который её использует, полагается на это поведение. Если Когда вы захотите изменить эту функцию, юнит-тест будет вам гарантировать, что
поведение функции осталось таким же (либо тест провалится). Следовательно остальной код не заметит изменения реализации функции, а это значит, что с этого момента вы можете спокойной менять любую часть кода: юнит-тесты не позволят вам что-нибудь сломать.

Второй юнит-тест

Следующий юнит-тест напишем для обратной функции преобразования строки в число с плавающей запятой:

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

Для демонстрации основных возможностей JUnit Framework, напишем примитивный класс на языке Java и будем над ним издеваться. Этот класс будет иметь два метода — нахождение факториала неотрицательного числа и суммы двух чисел. Кроме того, в экземпляре класса будет находится счетчик вызовов методов.

Теперь напишем Unit тесты. Для этого создадим класс с некоторым количеством тестовых методов. Естественно, класс может содержать и обычные вспомогательные методы. Чтобы runner тестов мог определить, кто есть кто, тестовые методы необходимо помечать аннтоацией @Test .

У аннотации могут быть проставлены такие параметры:

  • expected — указываем какое исключение будет сгенерировано методом (см. пример ниже);
  • timeout — через какое время в милисекундах прекратить выполнение теста и засчитать его как неуспешный.

Если вы хотите указать, что определенный тест необхдимо пропустить, то пометьте его аннотацией @Ignore . Хотя можно просто удалить аннотацию @Test .

Бывает такое, что для выполнения каждого тестового сценария вам необходим некоторый контекст, например, заранее созданные экземпляры классов. А после выполнения нужно освободить зарезервированные ресурсы. В этом случае вам понадобятся аннтоации @Before и @After . Метод, помеченный @Before будет выполняться перед каждым тестовым случаем, а метод, помеченный @After — после каждого тестового случая.

Если же инициализацию и освобождение ресурсов нужно сделать всего один раз — соответственно до и после всех тестов — то используйте пару аннотаций @BeforeClass и @AfterClass .

А вот и сам тестовый класс с несколькими тестовыми сценариями:

Метод calls тестирует правильность счетчика вызовов. Метод factorial проверяет правильность вычисления факториала для некоторых стандартных значений. Метод factorialNegative проверяет, что для отрицательных значений факотриала будет брошен IllegalArgumentException . Метод todo будет проигнорирован. Попробуйте убрать аннотацию @Ignore, когда будете экспериментировать с кодом.

Метод assertTrue проверяет, является ли результат выражения верным. Некоторые другие методы, которые могут пригодиться:

  • assertEquals — ожидаемый результат и полученный результат совпадают;
  • assertNull — результатом выражения есть null ;
  • assertNotNull — результат выражения отличен от null ;
  • assertSame — ожидаемый и полученный объекты это один и тот же объект.
  • fail — метод генерирует исключение AssertionError — добавляем туда, куда не должен дойти ход выполнения программы.

В нашем современном мире IDE умеют находить и просто запускать тесты в проекте. Но что делать, если вы хотите запустить их вручную с помощью программного кода. Для этого можно воспользоваться Runner’ом. Бывают текстовый — junit.textui.TestRunner , графические версии — junit.swingui.TestRunner, junit.awtui.TestRunner .

Но чуть более современный метод — это использование класса JUnitCore . Добавьте следующий метод main в класс MathFuncTest :

И результат выполнения:

run tests: 3
failed tests: 0
ignored tests: 1
success: true

Вот и все на сегодня. Уверен, JUnit Framework во многом поможет вам. Комментарии и вопросы по поводу статьи приветствуются.

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

О том, когда начинать автоматизировать тесты, описано в этой статье, о скиллах и трудностях перехода из "ручника" в автотестеры писали в этой статье.

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

  • Уметь писать чек-листы и тест-кейсы, иметь навык ручного тестирования;
  • Знать теоретическую базу и применять техники тест-дизайна: классы эквивалентности и граничные значения;
  • Иметь представление о том, как работают веб- или мобильные приложения.

Основы SQL для выполнения выборок данных;

Изучите JAVA CORE, основы объектно-ориентированного программирования;

Познакомьтесь с IntelliJ IDEA – научитесь создавать/запускать проект; посмотрите, как настраивать IDE под себя (хорошие советы по IntelliJ IDEA)

Познакомьтесь с структурой файлов в проекте;

Изучите паттерны разработки, распространенные в автоматизированным тестировании.

Например: Page Object, Fluent/Chain of invocations, Factory/Page Factory, Strategy, Data Patterns, Builder, Decorator (можно почитать тут);

Попробуйте подключить внешние библиотеки локально или репозиторий компании;

После того, как научитесь писать стандартные тесты, начните изучать заглушки (stub). Под заглушкой тут понимается самописное приложение (Например, на Java+Spring) или готовый инструмент (WireMock, MockServer) для имитации работы приложения, с которым мы работаем при интеграционном взаимодействии. MockServer позволяет легко написать динамические и статические заглушки (что-то можно сделать и в fiddler для оперативности);

Настройте pipeline с включением прогона автотестов в инструменте непрерывной интеграции Jenkins (можно скачать docker образ).

Читайте также: