Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

IPZ / IPZ_lab1_JUnit

.pdf
Скачиваний:
8
Добавлен:
07.02.2016
Размер:
589.13 Кб
Скачать

Лабораторная работа 1

"JUnit"

Цель – приобрести навыки работы с библиотекой тестирования "JUnit".

1. Теоретические сведения.

Процесс создания относительно сложных программных систем (работа над проектами) можно охарактеризовать следующим свойством:

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

Проведение процедуры тестирования призвано уменьшить число ошибок в программном коде. С этой целью может быть использована библиотека классов "JUnit". Библиотека подключается к создаваемому проекту в качестве соответствующего Java-архива (junit-4.11.jar). "JUnit" можно рассматривать в качестве программного инструментария для написания и прогона тестов. Этот инструментарий также был портирован и на другие языки программирования [1]: C# (NUnit), C++ (CPPUnit), Fortran (fUnit), PHP (PHPUnit), JavaScript (JSUnit).

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

Основные аннотации JUnit 4:

1.Аннотация @Before обозначает методы, которые будут вызваны до исполнения теста, методы должны быть public void. Здесь обычно размещаются предустановки для теста.

2.Аннотация @BeforeClass обозначает методы, которые будут вызваны до создания экземпляра тест-класса, методы должны быть public static void. Имеет смысл размещать предустановки для теста в случае, когда класс содержит несколько тестов использующих различные предустановки, либо когда несколько тестов используют одни и те же данные, чтобы не тратить время на их создание для каждого теста.

3.Аннотация @After обозначает методы, которые будут вызваны после выполнения теста, методы должны быть public void. Здесь размещаются операции освобождения ресурсов после теста.

4.Аннотация @AfterClass связана по смыслу с @BeforeClass, но выполняет методы после теста, как и в случае с @BeforeClass, методы должны быть public static void.

5.Аннотация Test обозначает тестовые методы. Эти методы должны быть public void. Здесь размещаются сами проверки. Кроме того, у данной аннотации есть два параметра, expected — задает ожидаемое исключение и timeout — задает время, по истечению которого тест считается провалившимся (например: @Test(expected =

NullPointerException.class) – ожидаемое исключение NullPointerException или

@Test(timeout = 1000) – задержка теста 1000 миллисекунд).

6.Если какой-либо тест по какой-либо серьезной причине нужно отключить(например, этот тест постоянно валится, но его исправление отложено до светлого будущего) его можно зааннотировать @Ignore. Также, если поместить эту аннотацию на класс, то все тесты в этом классе будут отключены. Аннотация Ignore может иметь параметр – причину пропуска теста (например: @Ignore(«Тест еще не готов»))

7.То, как запускается тест, тоже может быть сконфигурировано с помощью @RunWith. При этом класс, указанный в аннотации должен наследоваться от Runner. Рассмотрим запускалки, идущие в комплекте с самим фреймворком.

8.@Suite запускает несколько тестов в пакетном режиме. Для настройки запускаемых тестов используется аннотация @SuiteClasses.

9.@Categories - попытка организовать тесты в категории (группы). Для этого тестам задается категория с помощью @Category, затем настраиваются запускаемые категории тестов в сюите.

© Шкарупило В.В., Ильяшенко М.Б., Польская О.В.

1

10.@Parameterized — довольно интересная запускалка, позволяет писать параметризированные тесты. Для этого в тест-классе объявляется статический метод возвращающий список данных, которые затем будут использованы в качестве аргументов конструктора класса.

11.@Theories — чем-то схожа с предыдущей, но параметризирует тестовый метод, а не конструктор. Данные помечаются с помощью @DataPoints и @DataPoint, тестовый метод - с помощью @Theory.

Более полную документацию по модулю JUnit можно найти в [2].

Основные концепции JUnit приведены в табл. 1 [3].

Таблица 1 – Назначения основных объектов (JUnit core objects)

Объект (класс)

Описание

Assert

- определение утверждений, подлежащих

 

тестированию (проверке);

Test

- аннотация "@Test" определяет метод как

 

"тестовый";

TestCase

- класс-контейнер для "@Test"-методов;

Suite

- средство группировки тестируемых классов;

Runner

- средство прогона тестов;

Отдельного внимания заслуживает аннотация вида "@Test(timeout=var)", где "var" – значение в миллисекундах. Ее использование обосновано потребностью оценки временных издержек, связанных с получением результата работы тестируемого метода: если значение параметра "timeout" меньше оценочного значения, то тест автоматически расценивается как "failed".

Приведем некоторые из "Assert"-методов (табл. 2).

Таблица 2 – Методы сравнения объектов

Метод

Назначение

assertEquals(A, B);

- проверка равенства объектов A и B;

assertArrayEquals(A, B);

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

assertTrue(condition);

- проверка истинности условия

 

(логического высказывания);

assertFalse(condition);

- проверка ложности высказывания.

Замечания к табл. 2:

-методы имеют тип "static void";

-если в качестве аргументов метода "assertEquals" выступают параметры типа "double", то вводится также 3-й аргумент ("deviation") как разница между значениями 1-го и 2-го

аргументов: "assertEquals(double a, double b, deviation);".

Чтобы прогонять тесты несколько раз (с привязкой к различным наборам данных) проводят "параметризованное" тестирование. С этой целью используют аннотацию

(аннотацию) "@RunWith": @RunWith(value=Parameterized.class). Помимо этого также необходимо предварить метод, возвращающий наборы данных, подлежащих анализу,

аннотацией "@Parameterized.Parameters".

Чтобы использовать методы классов "Runner" и "Parameterized", необходимо импортировать следующие пакеты:

org.junit.runner.*; org.junit.runners.*;

© Шкарупило В.В., Ильяшенко М.Б., Польская О.В.

2

Класс "TestSuite" и группирование тестируемых классов: последняя выполняется с целью автоматизации процесса тестирования. В данном контексте корректно говорить о прогоне тестового набора ("suite").

Для вызова соответствующих методов необходимо импортировать следующие пакеты: org.junit.runner.RunWith;

org.junit.runners.Suite;

Также следует использовать аннотацию "@RunWith(Suite.class)".

2. Основная часть.

Задание 1. Создать в среде разработки "NetBeans" Java-проект (меню Файл > Создать проект > Java > Приложение Java; Имя проекта: Lab1-1), в котором, в свою очередь, создать файл "JUnit Test…" (меню Файл > Создать Файл > Модульные Тесты > Модуль тест JUnit; Имя класса: Tester).

В соответствующем рабочем каталоге ("test") по умолчанию будет сгенерирован *.java- файл-шаблон, содержимое которого следует отредактировать в соответствии с содержимым листинга 2.

Конструктор класса "Calc" рассмотрен в контексте метода, подлежащего проверке (листинг 1). Для создания класса Calc выполнить: меню Файл > Создать файл > Java > Класс

Java; Имя класса: Calc.

Для использования методов "JUnit"-классов следует подключить к проекту JAR-файл "junit-4.11.jar" (При использовании NetBeans версии 6.0 и выше класс JUnit 4.x уже включен в состав среды разработки).

Листинг 1 – Тестируемый класс package test;

public class Calc { private double result;

Calc(double A, double B) { result=A*B;

}

public double getResult() { return result;

}

}

Листинг 2 – Тестирующий класс package test;

import org.junit.Test;

import static org.junit.Assert.*; public class Tester {

@Test

public void Test() {

Calc calc = new Calc(3,3); assertEquals(calc.getResult(), 9, 0);

}

}

Примечание: для проведения тестирования в среде разработки "NetBeans" предназначена комбинация "Ctrl + F6" (поскольку тестирование реализовано в классе Tester, то нажимать сочетание клавиш необходимо находясь в окне редактирования класса Tester).

© Шкарупило В.В., Ильяшенко М.Б., Польская О.В.

3

Задание общее: создать условия, при которых результат тестирования метода "Test()" листинга 2 будет зависеть от временных издержек на получение результата работы метода. Для этого следует:

-заменить аннотацию "@Test" параметризованным аналогом;

-дополнить тело метода программным кодом, назначение которого подобно таковому, приведенному в листинге 3.

Листинг 3 – Создание задержки try {

Thread.sleep(milliseconds);

} catch (InterruptedException e) {}

Вариант 1 (Нечетный № ПК). Проверить равенство двух char-массивов, один из которых должен быть проинициализирован в конструкторе класса "Calc".

Реализовать в классе "Calc" метод расчета факториала и проверить его работоспособность путем вызова "Assert"-метода в классе "Tester".

Вариант 2 (Четный № ПК).Задания аналогичны таковым для 1-го варианта, однако: - проверке подлежит выполнимость условия равенства длин массивов;

- в классе "Calc" должен быть реализован метод генерации чисел Фибоначчи arr[i 2] arr[i 1] arr[i] .

Задание 2. Параметрическое тестирование. Рассмотрим пример тестирования (верификации) метода выявления простых (составных) чисел, определенного в классе

"PrimeChecker" (листинг 4).

Листинг 4 – Метод, подлежащий проверке package prime;

public class PrimeChecker {

public Boolean verify(Integer prime) { for(int i=2; i<prime/2; ++i) {

if(prime%i==0) return false; // complex number

}

return true;

}

}

Реализуем класс "PrimeCheckerTester" (листинг 5).

Листинг 5 – "Тестирующий" класс package prime;

import org.junit.runner.*; import org.junit.runners.*; import org.junit.Test;

import static org.junit.Assert.*; import java.util.Arrays;

import java.util.Collection;

@RunWith(Parameterized.class) public class PrimeCheckerTester {

private Integer

in;

 

private Boolean

expected;

 

private PrimeChecker pc;

 

public PrimeCheckerTester(Integer in, Boolean expected) {

 

 

 

 

 

© Шкарупило В.В., Ильяшенко М.Б., Польская О.В.

4

pc = new PrimeChecker(); this.in=in; this.expected=expected;

}

@Parameterized.Parameters

public static Collection getNumbers() { return Arrays.asList(new Object[][] {

{1, true },

{3, true },

{6, false },

{7, true }

});

}

@Test

public void Test() { assertEquals(expected, pc.verify(in));

}

}

Примечание: аннотацией @RunWith(Parameterized.class) мы указываем JUnit, что будет произведено пакетное тестирование с использованием метода-генератора набора тестирующих данных (в нашем случае это массив пар число-значение, возвращаемый статическим методом getNumbers()). Аннотация @Parameterized.Parameters указывает JUnit

какой именно метод будет использован для генерации тестовых наборов. Для корректной работы тестов тестирующий класс в обязательном порядке должен содержать конструктор, поскольку набор данных, полученный от метода-генератора будет вначале передан конструктора тестирующего класса для создания экземпляра этого класса (так же в конструкторе тестирующего класса проводится необходимая обработка исходных данных и преобразование типов при необходимости). После создания объекта класса PrimeCheckerTester для каждого набора тестовых данных вызывается метод помеченный аннотацией @Test который работает полностью аналогично однократному тестированию, рассмотренному в задании 1.

Задание общее: прокомментировать результат тестирования для листинга 5, а также результат тестирования для случая, если пару (1, "true") заменить парой (1, "false").

Вариант 1. Модифицируйте метод "verify()" класса "PrimeChecker" таким образом, чтобы осуществлялась проверка условия равенства двух строк, передаваемых в качестве аргументов метода.

В классе "PrimeCheckerTester" следует сгенерировать тестовые наборы вида (String, Boolean).

Вариант 2. Метод "verify()" класса "PrimeChecker" должен реализовать проверку равенства длин строк.

В классе "PrimeCheckerTester" следует сгенерировать тестовые наборы вида (Integer, Boolean).

Примечание (для обоих вариантов). Строка формируется из последовательности 3-х случайных целых чисел в интервале 1, 3 .

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

import java.util.Random;

...

Random r = new Random();

...

© Шкарупило В.В., Ильяшенко М.Б., Польская О.В.

5

arr[i]=r.nextInt(3)+1;

Формировать строку можно следующим образом: import java.lang.String;

...

str+=(String.format("%d", arr[i]));

Или иначе: str+=(Integer.toString(arr[i]));

Задание 3. Прогон тестовых наборов (класс "Suite").

Основываясь на содержимом листинга 6, создать класс ("TestSuite"), предназначенный для тестирования методов классов "Tester" и "PrimeCheckerTester" листингов 2 и 5 соответственно.

Листинг 6 – Шаблон "Suite"-тестера import org.junit.runner.RunWith; import org.junit.runners.Suite;

@RunWith(Suite.class)

@Suite.SuiteClasses({ <<class_name_1>>.class, <<class_name_2>>.class,

...

 

})

 

public class TestSuite {

}

Примечание: аннотация @RunWith(Suite.class) просто удобная "оболочка" дающая указание JUnit на запуск нескольких тестов подряд. Класс, указанный в качестве параметра (Suite.class) на самом деле так же является аннотацией JUnit в которой просто перечислены классы тестов которые должны быть выполнены в "пакетном" режиме (последовательно до первого "провалившегося" теста). Для создания набора тестов можно использовать мастер выбрав меню Файл > Создать файл > Модульные тесты > Набор тестов и отредактировать шаблон конструкции @RunWith(Suite.class) сгенерированной мастером согласно приведенному заданию.

Задание общее: провести "Suite"-тестирование путем прогона созданного "TestSuite"- теста. Прокомментировать результат (число тестов).

Вариант 1. Модифицировать содержимое листинга 2 так, чтобы результат соответствующего тестирования являл собой "fail"-результат. Провести "Suite"-тестирование, прокомментировав результат последнего.

Вариант 2. Задание аналогично таковому для 1-го варианта, однако модифицировать следует содержимое листинга 5, произвольным образом заменив две пары вида (Integer, Boolean). Прокомментировать результат "Suite"-тестирования.

Контрольные вопросы:

1.Опишите назначение "Assert"-методов и приведите примеры их использования.

2.Каков будет результат тестирования ("failed" или "passed"), если строку

"assertEquals(calc.getResult(), 9, 0);" листинга 2 заменить строкой "assertEquals(calc.getResult(), 8, 1);"? Прокомментировать.

3.Поясните назначение аннотации "@RunWith". Приведите пример.

© Шкарупило В.В., Ильяшенко М.Б., Польская О.В.

6

4.Опишите условия, при которых обоснованно использовать аннотацию вида

"@Test(timeout=var)". Приведите пример.

5.Опишите назначение "Suite"-тестирования. Приведите пример.

Литература

1.Переходим на JUnit 4 [Электронный ресурс] – Режим доступа: \www/ URL: http://www.ibm.com/developerworks/ru/edu/j-junit4/

2.JUnit API Documentation [Электронный ресурс] – Режим доступа: \www/ URL: http://junit.sourceforge.net/javadoc/

3.Tahchiev, P. JUnit in Action [Text] / P. Tahchiev, F. Leme, V. Massol, G. Gregory. – [2nd ed.]. –Stamford, CT, The USA: Manning Publications Co., 2010. – 504 p. – ISBN 978-1-935182-02-3.

© Шкарупило В.В., Ильяшенко М.Б., Польская О.В.

7

Соседние файлы в папке IPZ