Каждая выполненная задача в программировании требует тестирования, потому что от ошибок, как известно, никто не застрахован.
Зачастую на эту процедуру уходит немало времени, даже в простых задачах у новичков. Вы запускаете приложение, вводите данные для проверки и понимаете, что результат не соответствует ожиданиям. Затем вы начинаете выяснять, на каком же этапе произошла ошибка, все это у вас отнимает драгоценные минуты, которые вы могли бы потратить на разработку нового функционала.
А что если ваше приложение большое и в нем много зависящих друг от друга модулей, классов и компонент, и ваша задача — изменить поведение существующего кода, при этом не повредив старое?
В чем смысл Unit-тестов?
Именно для этого придумали юнит тесты, которые дают возможность автоматизировать проверку приложения.
Но ведь на написание тестов тоже уходит время — возразите вы и будете правы. Дело в том, что с ростом вашего приложения это время будет сокращаться, а без тестов ситуация обратная: чем сложнее становится приложение, тем более трудоемким будет его изменение и процесс отслеживания ошибок.
К тому же, не будем забывать, что интеграционное тестирование, которым пользуется большинство «смертных» программистов, требует запуска приложения, а, как известно из основ программирования Java, в Java развертывание и сборка — процесс не самый быстрый.
Помнится мне один банковский проект, в котором я тратил на это 15 минут, но не будем о грустном.
Для того, чтобы проникнуться данной концепцией, предлагаю почитать об экстремальном программировании. А пока давайте рассмотрим, какие инструменты нам предлагает Java для решения этой проблемы, и о том, как создать тест на Java.
Наиболее популярные — JUnit и TestNg, и речь сегодня пойдет о первом. Он является простым и гибким фреймворком для тестирования.
Рекомендуем курс по теме
JUnit аннотации и их описание
Пример Unit теста
Для того, чтобы подключить JUnit, нам необходимо добавить dependency в pom.xml, на момент написания статьи самая свежая версия 4.12:
Затем представим, для простоты понимания, что у нас есть класс калькулятор, который может прибавлять и вычитать:
Unit тест для такого класса будет выглядеть так:
- Размещаться данный класс должен в папке test, которая специально создана для хранения тестовых классов.
- Название класса должно соответствовать одной из масок: *Test, Test*, *TestCase для того, чтобы maven surefire plugin смог найти ваш тестовый класс.
- Методы должны иметь возвращаемый тип void в сигнатуре и аннотацию @Test, которая определяет, что метод является тестовым.
- Аннотация @Beforeуказываетна то, что метод будет выполняться перед каждым тестируемым методом.
Также для проверки результата используется специальный проверяемый метод assertEquals, который в нашем случае может принимать сообщение, которое будет показываться при несоответствии фактического и ожидаемого результата, затем второй параметр – фактический результат и третий ожидаемый результат.
Далее открываем терминал, перейдем в папку с нашим проектом и выполним mvn test:
По выводу лога консоли видно, что тесты прошли успешно. Если же мы изменим знак в методе add c + на *, то тест будет failed, и лог будет выглядеть так:
Таким образом, мы сразу видим, какой тест у нас не прошел проверку, и можем начать отладку с нужной точки.
Рекомендуем курс по теме
В следующей таблице приведен обзор имеющихся в аннотации JUnit 4.x.
Аннотация | Описание |
@Test public void method() public void method() public void method() public static void method() public static void method() | Аннотация @Test определяет что метод method() является тестовым. |
@Before | Аннотация @Before указывает на то, что метод будет выполнятся перед каждым тестируемым методом @Test. |
@After | Аннотация @After указываетна то что метод будет выполнятся после каждого тестируемого метода @Test |
@BeforeClass | Аннотация @BeforeClass указывает на то, что метод будет выполнятся в начале всех тестов, а точней в момент запуска тестов(перед всеми тестами @Test). |
@AfterClass | Аннотация @AfterClass указывает на то, что метод будет выполнятся после всех тестов. |
@Ignore | Аннотация @Ignore говорит, что метод будет проигнорирован в момент проведения тестирования. |
@Test (expected = Exception.class) | (expected = Exception.class) — указывает на то, что в данном тестовом методе вы преднамеренно ожидается Exception. |
@Test (timeout=1000) | (timeout=1000) — указывает, что тестируемый метод не должен занимать больше чем 1 секунду. |
Проверяемые методы (основные)
Метод | Описание |
fail(String) | Указывает на то что бы тестовый метод завалился при этом выводя текстовое сообщение. |
assertTrue([message], boolean condition) | Проверяет, что логическое условие истинно. |
assertsEquals([String message], expected, actual) | Проверяет, что два значения совпадают. Для массивов проверяются ссылки, а не содержание массивов. |
assertNull([message], object) | Проверяет, что объект является пустым null. |
assertNotNull([message], object) | Проверяет, что объект не является пустым null. |
assertSame([String], expected, actual) | Проверяет, что обе переменные относятся к одному объекту. |
assertNotSame([String], expected, actual) | Проверяет, что обе переменные относятся к разным объектам. |
Также я прикрепил пример с ООП моделью компании, в которой подсчитываются затраты на зарплату для сотрудников по компании и департаменту.
Основные методы покрыты unit тестами, код размещен тут.