Подготовка тестовых объектов

При написании тестов, даже самых простых, зачастую используются тестовые объекты. Например в статье про основные возможности JUnit я регулярно использовал следующую конструкцию:

Что не совсем хорошо: во-первых, это нарушает принцип DRY — Don’t Repeat Yourself (не повторяй себя); во-вторых, если б тестовые объекты были бы хоть немногим сложнее, их регулярное (пере-) создание вылилось бы в полный кошмар. Представьте себе, если бы Вы в каждом тестовом методе писали такое (осторожно, говнокод):

Ужасно! Представляете, 80% содержимого теста было бы простым созданием одних и тех же объектов. А уж когда эти объекты меняются, это был бы просто кошмар с переписыванием тестов.

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

Подготовка

Возьмём код из примера основной функциональности JUnit и скопируем класс StringUtilsTest  в StringUtilsSetupTest

Before/After

Любой public void  метод, с аннотацией @Before  будет вызван автоматически перед запуском каждого теста (то есть столько раз, сколько в классе
тестов). Традиционно такой метод называют setUp :

Используя эту возможность, перенесём создание тестовых данных в метод setUp():

Строку и массив, используемые в тестах, я вынес в члены класса и присваиваю им значение перед запуском каждого теста.  Теперь, когда мне надо будет изменить тестовые данные, я смогу это сделать в одном месте — в функции setUp()  и все остальные тесты, очевидно, будут использовать новые данные.

В случае, если бы я использовал какой-либо большой объект или объект, требующий какой-нибудь обработки после теста (закрытия файла, завершения транзакции, итд.), можно использовать аннотацию @After . Эта аннотация так же требует public void метод, который будет вызван после каждого теста. Традиционно такой метод называют tearDown:

В моём примере трудно найти полезное применение этому функционалу, но почему-бы не сбрасывать после каждого теста тестовую строку?

BeforeClass/AfterClass

Хороший, годный программист в этом месте спросит: «А зачем вообще перед каждым методом инициализировать строку? Почему нельзя обойтись одним разом, ведь строка не меняется?» и будет прав. Обычно аннотации @Before/@After  используют для тех тестовых данных, которые изменяются в ходе теста и, следовательно, требуют восстановления исходных значений.

Для значений, которые достаточно проинициализировать один раз или инициализация которых слишком медленна, чтобы делать это перед каждым тестом, предусмотрены аннотации @BeforeClass/@AfterClass . Методы, которые ими можно аннотировать, должны быть статическими, а поэтому работать они могут только с статическими членами класса. Я мог бы сделать переменные testString  и testArray  статическими, но в иллюстративных целях лучше заведу
новую тестовую переменную, с помощью которой проверю, как разбираются на массив длинные строки:

Обратите внимание, что функции, аннотированные @BeforeClass/@AfterClass  традиционно называеются setUpClass  и tearDownClass  соответственно.

В примере перед запуском тестов генерируется длинная строка, которая освобождается после выполнения всех тестов. Очевидно, что все изменения, внесённые тестами в эту переменную, сохраняются. Следует помнить, что порядок тестов в обычных условиях не определён и может меняться между запусками, если другое поведение не указано явно.

Исходный код примера доступен на github