Введение в JUnit

Часть третья, заключительная

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


Краткое содержание предыдущих серий

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

Итак, в первой части нашего разговора о JUnit'е мы с вами рассмотрели основные методы из арсенала данного фреймворка, применяемые для установления правильности работы отдельных "кусков" кода приложения. Методов этих было довольно много, и все перечислять я не буду, напомню только два наиболее часто используемых - assertEquals и assertSame. Отличаются, напомню, они тем, что первый сравнивает "содержимое" двух объектов с помощью вызова метода equals, а второй определяет, что две переменные ссылаются, фактически, на один и тот же объект.

В прошлый раз речь шла о том, как именно можно переопределять метод equals, чтобы корректно сравнивать друг с другом произвольные классы (а это в тестировании очень и очень важно), мы также разобрали первый простой тест, который проверял некоторую часть функциональности класса-калькулятора. Ну а ещё мы с вами немного поговорили о том, как добиться атомарности тестов при их последовательном "прогоне", т.е. как исключить влияние одного теста на результаты другого.

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


На старт... Внимание... Марш!

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

В том, чтобы запустить одиночный тест из среды Eclipse, ничего сложного как бы и нет. По крайней мере, для тех, кто хоть раз запускал на выполнение из неё хоть один проект. В контекстном меню (или в главном меню среды) нужно выбрать пункт "Run As", а в нём - "JUnit Test". Если вы всё правильно сделали при установке JUnit'а в Eclipse (а что-то сделать там неправильно было бы довольно-таки затруднительно), то сбоку, где панель с деревом проектов и деревом классов, появится ещё одна панель, на которой, конечно же, будут отображаться результаты запуска ваших тестов. Там всё изображено достаточно наглядно, и самостоятельно разобраться вам будет не сложно. Но, нужно сказать, что такой способ запуска тестов нельзя назвать самым удачным из всех существующих в силу вполне очевидных причин. Основная из них, конечно же, заключается в том, что запускать большое количество тестов по одному вручную из среды Eclipse - удовольствие, скажем прямо, весьма и весьма сомнительное. Поэтому стоит задуматься, как именно можно автоматизировать данный процесс. К счастью, это, оказывается, вовсе не так уж и сложно, потому что создатели фреймворка JUnit позаботились о том, чтобы дать возможность разработчику, пишущему с его помощью unit-тесты, "прогонять" их один за другим и следить за результатами. Но для этого нам нужно будет написать ещё немного дополнительного кода.

Следующий класс, с которым нам понадобится познакомиться, называется TestSuite. Данный класс как раз и предназначен для группирования тестов по какому-то определяемому самим программистом признаку. Ещё один полезный класс, который также будет нужен нам для запуска целого набора тестов, называется TestRunner. Название у него, что называется, говорящее и потому полностью отражающее суть работы данного класса. Скорее всего, вы будете использовать класс BaseTestRunner, либо писать какой-то потомок для данного класса, чтобы запускать тесты, входящие в набор, создаваемый с помощью TestSuite. Но, в принципе, это менее важный класс, чем TestSuite, поэтому мы займёмся сейчас именно классом TestSuite.

Итак, давайте посмотрим подробнее, как именно можно применять класс TestSuite, подозреваю, с ним пока мало что понятно. Разобраться нам поможет листинг.

import junit.framework.Test;
import junit.framework.TestSuite;
public class TestAll {
 public static Test suite() {
  TestSuite suite = new TestSuite("Running all available tests ");
  suite.addTestSuite(TestCounter.class);
  return suite;
 }
}

Что ж, начнем разбираться по порядку с каждой строчкой кода, приведенного в рассматриваемом нами листинге. Первые три - это, как водится, "импорты", нужные, чтобы компилятор нашёл используемые нами классы из состава фреймворка JUnit. Дальше объявляем класс, который будет запускать все доступные на данный момент JUnit-тесты, чтобы потом исправить найденные с их помощью ошибки в коде. Чтобы можно было запускать наш класс, потребуется метод suite(), являющийся, как несложно заметить, статическим и возвращающим экземпляр класса, реализующего интерфейс Test. Дальше по коду будет видно, что, фактически, возвращаемый методом объект будет принадлежать к классу TestSuite, который как раз и реализует этот интерфейс. Экземпляр этого класса мы создаём в следующей строке, присваивая его переменной suite. После того, как создан набор тестов, в него, конечно же, нужно добавить элементы, которые и будут выполнять тестирование приложения. Именно их добавлением мы и занимаемся в следующей строчке. Понятно, что если классов, которые тестируют функциональность кода, у нас несколько, то и добавлять их все нужно по очереди. Ну а завершается всё это действо победоносным возвращением экземпляра класса TestSuite, которое мы уже обсудили немного выше.

Итак, мы сделали по примеру приведенного в этой части статьи листинга класс, возвращающий экземпляр TestSuite, добавили туда всё что надо, и... "И что дальше?", - можете спросить вы. А дальше всё ещё проще. Приведенный класс можно запускать описанным выше способом как JUnit-тест, т.е. просто выбрав соответствующий пункт в меню среды Eclipse. Думаю, что с запуском тестов у вас проблем не должно возникнуть, тем более, что мы это уже достаточно подробно разобрали выше.


И ещё немного об атомарности тестов

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

Для этих целей в JUnit'е специально предусмотрен такой класс, как TestSetup. Использоваться он должен как оболочка для классов-наборов, а как именно используется, вам продемонстрирует листинг.

public static Test suite() {
 TestSuite suite = new TestSuite();
 suite.addTest(new TestClassTwo("test1"));
 suite.addTest(new TestClassTwo("test2"));
 TestSetup wrapper = new TestSetup(suite) {
  protected void setUp() { oneTimeSetUp(); }
  protected void tearDown() { oneTimeTearDown(); }
 };
 return wrapper;
}

В коде листинга, как видите, приведен только тот метод, который создаёт экземпляр TestSuite, вызываемый затем при выполнении тестов. Первые две строчки, я думаю, не вызовут ни у кого вопросов, как, собственно говоря, и следующие две, в которых мы добавляем в наш с вами набор тестов два теста (обратите внимание, что сейчас мы действуем немного не так, как в первом листинге). Дальше вызываем конструктор класса TestSetup, который создаёт для нас экземпляр данного класса, и в рамках данного экземпляра уже определяем методы setUp и tearDown, действующие совершенно аналогично рассмотренным нами в предыдущей части статьи одноименным методам, заложенным в интерфейс TestCase. Конечно, что уж тут говорить, "очистка" результатов деятельности целого набора тестов реализована в JUnit'е куда сложнее, чем она же для одного-единственного теста. Но здесь, сами понимаете, выбирать особенно не из чего и придётся смириться с тем, что всё реализовано именно так.


Резюме

Что ж, думаю, знакомство с замечательным фреймворком JUnit, который должен обязательно освоить каждый Java-программист, можно считать успешно состоявшимся. Конечно, за кадром осталась ещё масса разнообразных вопросов, но, уверен, если вы освоите азы JUnit'а, то сможете вполне успешно разрешать их самостоятельно. В конце концов, в трёх газетных статьях не уместишь даже сколько-нибудь подробное описание всех возможностей такого большого фреймворка, как JUnit. Впрочем, думаю, что эти статьи всё равно были полезны для тех, кто решил освоить unit-тестирование.

Вадим СТАНКЕВИЧ,
dreamdrusch@tut.by

Версия для печатиВерсия для печати

Номер: 

46 за 2009 год

Рубрика: 

Software
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!