Тестирование программы, JUnit
JUnit — библиотека для модульного тестирования программ Java. Созданный Кентом Беком и Эриком Гаммой, JUnit принадлежит семье фреймворков xUnit для разных языков программирования, берущей начало в SUnit Кента Бека для Smalltalk. JUnit породил экосистему расширений — JMock, EasyMock, DbUnit, HttpUnit и т. д.
Библиотека JUnit была портирована на другие языки, включая PHP (PHPUnit), C# (NUnit), Python (PyUnit), Fortran (fUnit), Delphi (DUnit), Free Pascal (FPCUnit), Perl (Test::Unit), C++ (CPPUnit), Flex (FlexUnit), JavaScript (JSUnit).
JUnit – это Java фреймворк для тестирования, т. е. тестирования отдельных участков кода, например, методов или классов. Опыт, полученный при работе с JUnit, важен в разработке концепций тестирования программного обеспечения.
Пример теста JUnit
Необходимость использования JUnit
JUnit позволяет в любой момент быстро убедиться в работоспособности кода. Если программа не является совсем простой и включает множество классов и методов, то для её проверки может потребоваться значительное время. Естественно, что данный процесс лучше автоматизировать. Использование JUnit позволяет проверить код программы без значительных усилий и не занимает много времени.
Юнит тесты классов и функций являются своего рода документацией к тому, что ожидается в результате их выполнения. И не просто документацией, а документацией которая может автоматически проверять код на соответствие предъявленным функциям. Это удобно, и часто тесты разрабатывают как вместе, так и до реализации классов. Разработка через тестирование — крайне популярная технология создания серьезного программного обеспечения.
Виды тестирования и место JUnit тестирования в классификации
Тестирование программного обеспечение можно разделить на два вида:
Во время тестирования программы как черного ящика внутренняя структура приложения в расчет не принимается. Все, что имеет значение, это функциональность, которую приложение должно обеспечить. При тестировании программы как белого ящика во внимание принимается внутренняя структура, т.е. класс и методы. Кроме этого, тестирование можно разделить на четыре уровня:
Юнит тестирование по определению является тестированием белого ящика.
JUnit 3
Для создания теста следует наследовать тест-класс TestCase, переопределить методы setUp и tearDown при необходимости, ну и самое главное — разработать тестовые методы, наименование которых должно начинаться с аббривиатуры «test». При запуске теста сначала создается экземляр тест-класса (для каждого теста в классе отдельный экземпляр класса), затем выполняется метод setUp, запускается сам тест, ну и в завершение выполняется метод tearDown. Если какой-либо из методов вызывает исключение, тест считается провалившимся.
Примечание : тестовые методы должны быть public void, могут быть static.
Тесты состоят из выполнения некоторого кода и проверок. Проверки чаще всего выполняются с помощью класса Assert хотя иногда используют ключевое слово assert.
В качестве примера рассмотрим утилиту для работы со строками, включающую методы для проверки пустой строки и представления последовательности байт в виде 16-ричной строки:
Дополнительные возможности, TestSuite
JUnit 3 имеет несколько дополнительных возможностей. Например, можно группировать тесты. Для этого необходимо использовать класс TestSuite:
Можно исполнение теста повторить несколько раз. Для этого используется RepeatedTest :
Наследуя тест-класс от ExceptionTestCase, можно проверить код на выброс исключения :
JUnit 4
В JUnit 4 добавлена поддержка новых возможностей из Java 5.0; тесты могут быть объявлены с помощью аннотаций. При этом существует обратная совместимость с предыдущей версией фреймворка. Практически все рассмотренные выше примеры будут работать и в JUnit 4 за исключением RepeatedTest, который отсутствует в новой версии.
Какие внесены изменения появились в JUnit 4? Рассмотрим тот же пример, но уже с использованием новых возможностей :
Примеры использования аннотаций с параметрами, JUnit Test :
Игнорирование выполнения теста, JUnit Ignore
Если один из тестов по какой-либо серьезной причине необходимо отключить, например, тест постоянно завершается с ошибкой. Исправление теста можно отложить до светлого будущего аннотированием @Ignore. Если поместить эту аннотацию на класс, то все тесты в этом классе будут отключены.
Правила тастирования, JUnit Rule
JUnit позволяет использовать определенные разработчиком правила до и после выполнения теста, которые расширяют функционал. Например, есть встроенные правила для задания таймаута для теста (Timeout), для задания ожидаемых исключений (ExpectedException), для работы с временными файлами(TemporaryFolder) и др.
Для объявления правила необходимо создать public не static поле типа производного от MethodRule и аннотировать его с помощью ключевого слова Rule.
Наборы тестов, JUnit Suite, SuiteClasses
Запуск теста может быть сконфигурирован с помощью аннотации @RunWith. Тестовые классы, которые содержат в себе тестовые методы, можно объединить в наборы тестов (Suite). Например, создано два класса тестирования объектов : TestFilter, TestConnect. Эти два тестовых класса можно объединить в один тестовый класс TestWidgets.java :
Для настройки запускаемых тестов используется аннотация @SuiteClasses, в которую включены тестовые классы.
Аннотация Categories
Аннотация Categories позволяет объединить тесты в категории (группы). Для этого в тесте определяется категория @Category, после чего настраиваются запускаемые категории тестов в Suite. Это может выглядеть следующим образом:
Аннотация, JUnit Parameterized
Аннотация Parameterized позволяет использовать параметризированные тесты. Для этого в тест-классе объявляется статический метод, возвращающий список данных, которые будут использованы в качестве аргументов конструктора класса.
Параметризирование метода : Theories.class, DataPoints, DataPoint, Theory
Аннотация Theories параметризирует тестовый метод, а не конструктор. Данные помечаются с помощью @DataPoints и @DataPoint, тестовый метод — с помощью @Theory. Тест, использующий этот функционал, может выглядеть примерно следующим образом :
Порядок выполнения тестов
Если необходимо выполнить тест в определенном порядке, то можно воспользоваться аннотацией @FixMethodOrder(MethodSorters.NAME_ASCENDING), определенной в JUnit 4.11. Например :
В противном случае можно использовать следующие 2 подхода.
Список основных аннотаций
| Аннотация | Описание |
|---|---|
| @Test public void testMethod() | метод является тестовым |
| @Test(timeout=100) public void testMethod() | если время выполнения превысит параметр timeout, то тест будет завершен неудачно |
| @Test (expected = MyException.class) public void testMethod() | метод должен выбросить исключение принадлежащие к классу MyException, в противном случае тест будет завершен неудачно |
| @Ignore public void testMethod() | игнорировать тестовый метод |
| @BeforeClass public static void testMethod() | метод вызывающийся один раз для класса перед выполнением тестовых методов; здесь можно разместить инициализацию которую нужно выполнять только один раз, например, прочитать данные, которые будут использоваться в тестовых методах или создать соединение с базой данных |
| @AfterClass public static void testMethod() | метод вызывающийся один раз для класса после выполнения тестовых методов; здесь можно разместить деинициализацию которую нужно выполнять только один раз, например, закрыть соединение с базой данных или удалить данные, которые больше не нужны |
| @Before public static void beforeMethod() | метод, вызывающийся перед каждым тестовым методом в тестовом классе; здесь можно выполнить необходимую инициализацию, например, выставить начальные параметры |
| @After public static void afterMethod() | метод, вызывающийся после каждого тестового метода в тестовом классе; здесь можно выполнить необходимую деинициализацию, например, удалить данные, которые больше не нужны |
Список типов проверок Asserts
| Тип проверки | Описание |
|---|---|
| fail() fail(String message) | прерывание теста с ошибкой, т.е. тест будет неудачным |
| assertTrue(boolean condition) assertTrue(java.lang.String message, boolean condition) | проверка на равенство условия condition значению true |
| assertFalse(boolean condition) assertFalse(String message, boolean condition) | проверка на равенство условия condition значению false |
| assertEquals( expected, actual) assertEquals(String message, expected, actual) | проверка на равенство; — это Object, int, double и т.д. |
| assertArrayEquals(byte[] expecteds, byte[] actuals) assertArrayEquals(String message, [] expecteds, [] actuals) | проверка массивов на равенство; аналогично assertEquals; — это Object, int, double и т.д. |
| assertNotNull(Object object) assertNotNull(String message, Object object) | проверка, что Object не null |
| assertNull(Object object) assertNull(String message, Object object) | проверка, что Object null |
| assertSame(Object expected, Object actual) assertSame(String message, Object expected, Object actual) | проверка на равенство двух объектов expected и actual, т.е. один и тот же объект |
Пример JUnit тестирования
Тестовый класс с несколькими сценариями будет иметь следующий вид :
Метод calls тестирует правильность счетчика вызовов. Метод factorial проверяет правильность вычисления факториала для некоторых стандартных значений. Метод factorialNegative проверяет, что для отрицательных значений факотриала будет брошен IllegalArgumentException. Метод todo будет проигнорирован.
В заключении следует отметить, что в статье представлены не все возможности использования JUnit. Но как видно из приведенных примеров, фреймворк достаточно прост в использовании, дополнительных возможностей немного, но есть возможность расширения с помощью правил и запускалок.
Основы JUnit
Когда делаешь первые попытки писать юнит-тесты обычно обычно сталкиваешься с проблемой начинания: вроде бы документация прочитана, цель ясна, а с чего начинать — не понятно.
Попробуем вместе написать простой юнит-тест, для более-менее настоящего класса, в котором испытаем почти весь базовый функционал JUnit.
Подготовка
Создадим пустой maven проект:
Класс для тестирования
Поскольку я обещал почти настоящий пример, придётся написать хоть сколько-то полезный класс. Пускай это будем набор утилит для работы со строками:
Тесты
Название тестовых методов так же могут быть любыми, однако для повышения читаемости кода, рекомендуется начинать их с префикса test * и отражать в названии суть теста.
Первый юнит-тест
В первом юнит-тесте строка
и есть входные данные, которые мы отдаём в проверяемую функцию.
Эталонные данные определены в следующей строке:
Вызываем проверяемый код и сохраняем результат его работы:
Наконец самая главная часть теста, проверка:
Однако с сообщением результаты тестирования становятся гораздо приятнее при чтении.
Более того, сам юнит-тест уже является краткой и понятной документацией к функции. В четырёх строках чётко и однозначно написано, как ведёт себя функция: возвращает новый строковый объект, значение которого является переданным ей числом с плавающей запятой, записанное в десятичной системе счисления.
А самый главный бонус юнит-тестирования, это фиксация поведения кода. Вы знаете, прямо сейчас, что функция ведёт себя определённым образом. И код, который её использует, полагается на это поведение. Если Когда вы захотите изменить эту функцию, юнит-тест будет вам гарантировать, что
поведение функции осталось таким же (либо тест провалится). Следовательно остальной код не заметит изменения реализации функции, а это значит, что с этого момента вы можете спокойной менять любую часть кода: юнит-тесты не позволят вам что-нибудь сломать.
Второй юнит-тест
Следующий юнит-тест напишем для обратной функции преобразования строки в число с плавающей запятой:
Основы JUnit
JUnit – фреймворк для модульного тестирования Java программ, принадлежащий семейству фреймворков xUnit для различных языков программирования (например: CPPUnit – C++, JSUnit – JavaScript, NUnit — C#, PHPUnit — PHP). Основная идея модульного тестирования заключается в проверке корректности работы отдельных модулей исходного кода программы, в условиях изолированности тестируемого модуля от других. JUnit играет важнейшую роль в технике разработки через тестирование (test-driven development – TDD), которая заключается в повторении очень коротких циклов разработки: сначала пишется тест, покрывающий желаемое изменение, и только затем пишется код, который позволит пройти этот тест.
Будет рассматриваться API версии 4 и выше, которая значительно отличается от версии 3.8. В обзоре раскрываются основы написания простейших JUnit тестов, приводится типовой набор утверждений (assert-ов) и правила определения фикстур (fixtures). Умышлено не приводятся описание работы с runner-ом, параметризованного тесстирования, ruler`s, различных подходов к работе с исключениями и другие возможности (так сказать вариант для чайников).
Для реализации Unit тестов организуется отдельный класс, который содержит сами тестовые методы (по правилам JUnit они должны быть public void, имена — произвольны), так же в этом классе могут содержаться обычные и вспомогательные методы. В более ранних версиях тестирующий класс должен был быть наследником junit.framework.TestCase, а все тестовые методы должны были начинаться с «test» (Например testSum), теперь все это заменяется аннотациями. Чтобы runner тестов мог определить, что это тестовый метод, его необходимо пометить аннотацией @Test. У аннотации @Test могут быть представлены следующие параметры (по отдельности или через запятую):
В случае необходимости пропустить какой либо тест, нужно либо просто убрать аннотацию @Test перед тестовым методом, либо добавить перед ней аннотацию @Ignore. При этом в качестве параметра можно указать причину пропуска теста. Пример:
По ссылке можно ознакомиться со способом организовать пропуск тестов при выполнении определенного условия основанный на применении «предположений» (assumption).
Тестовые методы строятся вокруг проверки утверждений (assert), представляющих собой статические методы определенные в классе Assert. Полный список доступных утверждений можно посмотреть по ссылке — https://junit.sourceforge.net/javadoc/org/junit/Assert.html. Каждому утверждению можно добавить первым параметром строку, которая будет выводиться в случае провала теста. Ниже представлен основной набор из наиболее часто используемых assert-ов.
Пример записи теста:
Подразумевается наличие тестируемого класса MyClass в котором определен статический метод multiply(double a, double b), возвращающий результат перемножения a и b. Четвертый параметр в assertEquals задает точность сравнения вещественных чисел.
Фикстура (англ. fixtures) – заранее подготовленное состояние окружения тестирования, требуемое для гарантии повторяемости процесса. Простыми словами это начальное состояние среды перед запуском тестовых методов (набор экземпляров классов, определенное состояние БД, наличиенеобходимых файлов и т.д.). Для задания фикстуры и высвобождения зарезирвированных ресурсов после выполнения теста применяются методы помеченные аннотациями @Before и @After. Метод, помеченный аннотацией @Before будет выполняться перед каждым тестовым случаем, а помеченный @After — после каждого тестового случая. Бывают случаи, когда необходимо провести инициализацию и высвобождение ресурсов всего один раз (до и после выполнения всех тестов). Для этого можно применить соответствующие аннотации – @BeforeClass и @AfterClass.
Порядок вызова методов проиллюстрирован следующим примером:
Стоит помнить, что каждый тест выполняется отдельно от других в произвольном порядке (хотя можно настроить порядок выполнения). Поэтому, в общем случае, тесты не должны зависеть друг от друга.
Тестирование в Java. JUnit

Сегодня все большую популярность приобретает test-driven development(TDD), техника разработки ПО, при которой сначала пишется тест на определенный функционал, а затем пишется реализация этого функционала. На практике все, конечно же, не настолько идеально, но в результате код не только написан и протестирован, но тесты как бы неявно задают требования к функционалу, а также показывают пример использования этого функционала.
Итак, техника довольно понятна, но встает вопрос, что использовать для написания этих самых тестов? В этой и других статьях я хотел бы поделиться своим опытом в использовании различных инструментов и техник для тестирования кода в Java.
Ну и начну с, пожалуй, самого известного, а потому и самого используемого фреймворка для тестирования — JUnit. Используется он в двух вариантах JUnit 3 и JUnit 4. Рассмотрю обе версии, так как в старых проектах до сих пор используется 3-я, которая поддерживает Java 1.4.
Я не претендую на автора каких-либо оригинальных идей, и возможно многим все, о чем будет рассказано в статье, знакомо. Но если вам все еще интересно, то добро пожаловать под кат.
JUnit 3
Для создания теста нужно унаследовать тест-класс от TestCase, переопределить методы setUp и tearDown если надо, ну и самое главное — создать тестовые методы(должны начинаться с test). При запуске теста сначала создается экземляр тест-класса(для каждого теста в классе отдельный экземпляр класса), затем выполняется метод setUp, запускается сам тест, ну и в завершение выполняется метод tearDown. Если какой-либо из методов выбрасывает исключение, тест считается провалившимся.
Примечание: тестовые методы должны быть public void, могут быть static.
Сами тесты состоят из выполнения некоторого кода и проверок. Проверки чаще всего выполняются с помощью класса Assert хотя иногда используют ключевое слово assert.
Рассмотрим пример. Есть утилита для работы со строками, есть методы для проверки пустой строки и представления последовательности байт в виде 16-ричной строки:
Напишем для нее тесты, используя JUnit 3. Удобнее всего, на мой взгляд, писать тесты, рассматривая нейкий класс как черный ящик, писать отдельный тест на каждый значимый метод в этом классе, для каждого набора входных параметров какой-то ожидаемый результат. Например, тест для isEmpty метода:
Можно разделить данные и логику теста, перенеся создание данных в метод setUp:
Дополнительные возможности
Кроме того, что было описано, есть еще несколько дополнительных возможностей. Например, можно группировать тесты. Для этого нужно использовать класс TestSuite:
Можно запустить один и тот же тест несколько раз. Для этого используем RepeatedTest:
Наследуя тест-класс от ExceptionTestCase, можно проверить что-либо на выброс исключения:
Как видно из примеров все довольно просто, ничего лишнего, минимум нужный для тестирования(хотя недостает и некоторых нужных вещей).
JUnit 4
Здесь была добавлена поддержка новых возможностей из Java 5, тесты теперь могут быть объявлены с помощью аннотаций. При этом существует обратная совместимость с предыдущей версией фреймворка, практически все рассмотренные выше примеры будут работать и здесь(за исключением RepeatedTest, его нет в новой версии).
Итак, что же поменялось?
Основные аннотации
Рассмотрим тот же пример, но уже используя новые возможности:
Если какой-либо тест по какой-либо серьезной причине нужно отключить(например, этот тест постоянно валится, но его исправление отложено до светлого будущего) его можно зааннотировать @Ignore. Также, если поместить эту аннотацию на класс, то все тесты в этом классе будут отключены.
Правила
Кроме всего вышеперечисленного есть довольно интересная вещь — правила. Правила это некое подобие утилит для тестов, которые добавляют функционал до и после выполнения теста.
Например, есть встроенные правила для задания таймаута для теста(Timeout), для задания ожидаемых исключений(ExpectedException), для работы с временными файлами(TemporaryFolder) и д.р. Для объявления правила необходимо создать public не static поле типа производного от MethodRule и зааннотировать его с помощью Rule.
Также в сети можно найти и другие варианты использования. Например, здесь рассмотрена возможность параллельного запуска теста.
Запускалки
Но и на этом возможности фреймворка не заканчиваются. То, как запускается тест, тоже может быть сконфигурировано с помощью @RunWith. При этом класс, указанный в аннотации должен наследоваться от Runner. Рассмотрим запускалки, идущие в комплекте с самим фреймворком.
JUnit4 — запускалка по умолчанию, как понятно из названия, предназначена для запуска JUnit 4 тестов.
JUnit38ClassRunner предназначен для запуска тестов, написанных с использованием JUnit 3.
SuiteMethod либо AllTests тоже предназначены для запуска JUnit 3 тестов. В отличие от предыдущей запускалки, в эту передается класс со статическим методом suite возвращающим тест(последовательность всех тестов).
Suite — эквивалент предыдущего, только для JUnit 4 тестов. Для настройки запускаемых тестов используется аннотация @SuiteClasses.
Enclosed — то же, что и предыдущий вариант, но вместо настройки с помощью аннотации используются все внутренние классы.
Categories — попытка организовать тесты в категории(группы). Для этого тестам задается категория с помощью @Category, затем настраиваются запускаемые категории тестов в сюите. Это может выглядеть так:
Parameterized — довольно интересная запускалка, позволяет писать параметризированные тесты. Для этого в тест-классе объявляется статический метод возвращающий список данных, которые затем будут использованы в качестве аргументов конструктора класса.
Theories — чем-то схожа с предыдущей, но параметризирует тестовый метод, а не конструктор. Данные помечаются с помощью @DataPoints и @DataPoint, тестовый метод — с помощью Theory. Тест использующий этот функционал будет выглядеть примерно так:
Как и в случае с правилами, в сети можно найти и другие варианты использования. Например, здесь рассмотрена та же возможность паралельного запуска теста, но с использованием запускалок.
Вывод
Это, конечно же, не все, что можно было сказать по JUnit-у, но я старался вкратце и по делу. Как видно, фреймворк достаточно прост в использовании, дополнительных возможностей немного, но есть возможность расширения с помощью правил и запускалок. Но несмотря на все это я все же предпочитаю TestNG с его мощным функционалом, о котором и расскажу в следующей статье.
5) Джунит Assert
Что такое Junit Assert?
Assert — это метод, полезный при определении статуса Pass или Fail тестового примера. Методы assert предоставляются классом org.junit.Assert, который расширяет класс java.lang.Object.
Существуют различные типы утверждений, такие как логические, нулевые, идентичные и т. Д.
Junit предоставляет класс с именем Assert, который предоставляет набор методов утверждений, полезных при написании тестовых случаев и для обнаружения неудачных тестов.
В этом уроке вы узнаете
Методы JUnit Assert
логический
Если вы хотите проверить логические условия (true или false), вы можете использовать следующие методы assert
Здесь условие является логическим значением.
Нулевой объект
Если вы хотите проверить начальное значение объекта / переменной, у вас есть следующие методы:
Здесь объект является Java- объектом, например, assertNull (фактический);
идентичный
Если вы хотите проверить, идентичны ли объекты (т. Е. Сравнивают две ссылки на один и тот же объект Java) или разные.
Утвердить равными
Если вы хотите проверить равенство двух объектов, у вас есть следующие методы
Assert Array Equals
Если вы хотите проверить равенство массивов, у вас есть следующие методы, как указано ниже:
Вышеупомянутый метод должен использоваться, если массивы имеют одинаковую длину, для каждого действительного значения для i вы можете проверить его, как указано ниже:
Сообщение об ошибке
Если вы хотите выбросить какую-либо ошибку подтверждения, у вас есть fail (), которая всегда приводит к отказу.
Вы можете использовать метод утверждения с дополнительным параметром String в качестве первого параметра. Эта строка будет добавлена в сообщение об ошибке, если утверждение не выполнено. Например, ошибка (сообщение) может быть записана как
JUnit assertEquals
У вас есть assertEquals (a, b), который опирается на метод equals () класса Object.
Например: рассмотрим нижеприведенные строки, имеющие одинаковые значения, давайте проверим это с помощью assertTrue
Выше оператор assert вернет true, так как obj1.equals (obj2) возвращает true.
Утверждения с плавающей точкой
Если вы хотите сравнить типы с плавающей запятой (например, double или float ), вам нужен дополнительный обязательный параметр delta, чтобы избежать проблем с ошибками округления при выполнении сравнений с плавающей запятой.



