- •724 Содержание
- •Глава 6. Интерфейсы и внутренние классы 139
- •У казания и ответы
- •Вопрос 3.2.
- •Вопрос 8.2.
- •Вопрос 8.3.
- •Вопрос 14.2.
- •Вопрос 21.5.
- •Ч асть 1. Основы языка java
- •Глава 1 введение в классы и объекты Основные понятия ооп
- •Язык Java
- •Нововведения версий 5.0 и 6.0
- •Простое приложение
- •Классы и объекты
- •Сравнение объектов
- •Консоль
- •Простой апплет
- •Задания к главе 1 Вариант a
- •Вариант b
- •Тестовые задания к главе 1
- •Вопрос 1.5.
- •Г лава 2 типы данных и операторы
- •Базовые типы данных и литералы
- •Документирование кода
- •Операторы
- •Классы-оболочки
- •Операторы управления
- •Массивы
- •Класс Маth
- •Управление приложением
- •Задания к главе 2 Вариант a
- •Вариант в
- •Тестовые задания к главе 2
- •Переменные класса и константы
- •Ограничение доступа
- •Конструкторы
- •Статические методы и поля
- •Модификатор final
- •Абстрактные методы
- •Модификатор native
- •Модификатор synchronized
- •Логические блоки
- •Перегрузка методов
- •Параметризованные классы
- •Параметризованные методы
- •Методы с переменным числом параметров
- •Перечисления
- •1 : Fpmi : Балаганов
- •Аннотации
- •Задания к главе 3 Вариант a
- •Вариант b
- •Тестовые задания к главе 3
- •Использование final
- •Использование super и this
- •Переопределение методов и полиморфизм
- •Методы подставки
- •Полиморфизм и расширяемость
- •Статические методы и полиморфизм
- •Абстракция и абстрактные классы
- •Класс Object
- •Клонирование объектов
- •“Сборка мусора” и освобождение ресурсов
- •Задания к главе 4 Вариант a
- •Вариант в
- •Тестовые задания к главе 4
- •Вопрос 4.7.
- •Г лава 5 проектирование классов Шаблоны проектирования grasp
- •Шаблон Expert
- •Шаблон Creator
- •Шаблон Low Coupling
- •Шаблон High Cohesion
- •Шаблон Controller
- •Шаблоны проектирования GoF
- •Порождающие шаблоны
- •К порождающим шаблонам относятся:
- •Шаблон Factory
- •Шаблон AbstractFactory
- •Шаблон Builder
- •Шаблон Singleton
- •Структурные шаблоны
- •К структурным шаблонам относятся:
- •Шаблон Bridge
- •Шаблон Decorator
- •Шаблоны поведения
- •К шаблонам поведения относятся:
- •Шаблон Command
- •Шаблон Strategy
- •Шаблон Observer
- •Тестовые задания к главе 5
- •Статический импорт
- •Внутренние классы
- •Внутренние (inner) классы
- •Вложенные (nested) классы
- •Анонимные (anonymous) классы
- •Задания к главе 6 Вариант а
- •Вариант b
- •Вариант c
- •Тестовые задания к главе 6
- •Вопрос 6.5.
- •Класс String
- •Классы StringBuilder и StringBuffer
- •Форматирование строк
- •Лексический анализ текста
- •Регулярные выражения
- •Интернационализация текста
- •Интернационализация чисел
- •Интернационализация дат
- •3 Апрель 2006 г.
- •Задания к главе 7 Вариант a
- •Вариант b
- •Тестовые задания к главе 7
- •Оператор throw
- •Ключевое слово finally
- •Собственные исключения
- •Наследование и исключения
- •Отладочный механизм assertion
- •Задания к главе 8
- •Байтовые и символьные потоки ввода/вывода
- •Предопределенные потоки
- •Сериализация объектов
- •Консоль
- •Класс Scanner
- •Архивация
- •Задания к главе 9 Вариант a
- •Вариант b
- •Вариант с
- •Тестовые задания к главе 9
- •Множества
- •Карты отображений
- •14El - найден по ключу '12'
- •Унаследованные коллекции
- •Класс Collections
- •Класс Arrays
- •Задания к главе 10 Вариант a
- •Вариант b
- •Тестовые задания к главе 10
- •Апплеты
- •Задания к главе 11
- •Тестовые задания к главе 11
- •Классы-адаптеры
- •Задания к главе 12
- •Тестовые задания к главе 12 Вопрос 12.1.
- •Вопрос 12.2.
- •Вопрос 12.3.
- •Вопрос 12.4.
- •Вопрос 12.5.
- •Г лава 13 элементы компоновки и управления
- •Менеджеры размещения
- •Элементы управления
- •Визуальные компоненты JavaBeans
- •Задания к главе 13 Вариант а
- •Вариант b
- •Жизненный цикл потока
- •Управление приоритетами и группы потоков
- •Управление потоками
- •Потоки-демоны
- •Потоки в графических приложениях
- •Методы synchronized
- •Инструкция synchronized
- •Состояния потока
- •Потоки в j2se 5
- •Задания к главе 14 Вариант а
- •Вариант b
- •Тестовые задания к главе 14
- •Вопрос 14.1.
- •Вопрос 14.2.
- •Вопрос 14.3.
- •Вопрос 14.4.
- •Вопрос 14.5.
- •Г лава 15 сетевые программы Поддержка Интернет
- •Сокетные соединения по протоколу tcp/ip
- •Многопоточность
- •Датаграммы и протокол udp
- •Задания к главе 15 Вариант а
- •Вариант b
- •Древовидная модель
- •Элементы таблицы стилей
- •Задания к главе 16 Вариант а
- •Тестовые задания к главе 16
- •Запуск контейнера сервлетов и размещение проекта
- •Первая jsp
- •Взаимодействие сервлета и jsp
- •Задания к главе 17 Вариант а
- •Вариант b
- •Интерфейс ServletContext
- •Интерфейс ServletConfig
- •Интерфейсы ServletRequest и HttpServletRequest
- •Интерфейсы ServletResponse и HttpServletResponse
- •Обработка запроса
- •Многопоточность
- •Электронная почта
- •Задания к главе 18 Вариант а
- •Вариант b
- •Стандартные элементы action
- •Неявные объекты
- •Демонстрация работы тегов c:forEach, c:choose, c:when, c:otherwise
- •Данная страница демонстрирует работу тегов
- •Включение ресурсов
- •Обработка ошибок
- •Технология взаимодействия jsp и сервлета
- •Задания к главе 19
- •Вариант а
- •Вариант b
- •Субд MySql
- •Простое соединение и простой запрос
- •Метаданные
- •Подготовленные запросы и хранимые процедуры
- •Транзакции
- •Id студента: 83, Petrov Внесены данные в students: 83, Petrov Внесены данные в course: 83, xml Данные внесены - транзакция завершена
- •Точки сохранения
- •Пул соединений
- •Задания к главе 20 Вариант а
- •Вариант b
- •Обработка событий
- •Фильтры
- •Задания к главе 21 Вариант а
- •Вариант b
- •Вопрос 21.5.
- •Вопрос 21.6.
- •Г лава22 пользовательские теги
- •Простой тег
- •Тег с атрибутами
- •Тег с телом
- •Элементы action
- •Задания к главе 22 Вариант а
- •Вариант b
- •П риложение 2
- •Включение скриптов на языке JavaScript в html-код
- •Отладка скриптов JavaScript
- •Типы данных
- •Специальные числа
- •Булев тип
- •Переменные типа Undefined и Null
- •Массивы
- •Операторы и выражения
- •Оператор with
- •Оператор switch
- •Метод eval()
- •Функции
- •Передача параметров по значению и по ссылке
- •Глобальные и локальные переменные
- •Пользовательские объекты
- •Прототипы
- •Встроенные объекты Array, Date, Math Объект Array
- •Объект Date
- •Объект Math
- •Объекты window и document
- •Создание новых узлов
- •Добавление новых узлов в документ
- •Удаление и замена узлов в документе
- •Использование каскадных таблиц стилей в dom
- •Свойство элемента innerHtml и outerHtml
- •Динамическое назначение событий
- •Ключевое слово this
- •П риложение3
- •Проектная модель
- •Uml как программный язык
- •Нотации и метамодель
- •Диаграммы, которые ниже будут рассмотрены с разной степенью детализации:
- •Свойства
- •Множественность
- •Операторы
- •П риложение 4 базы данных и язык sql
- •Реляционные субд Модель данных в реляционных субд
- •Нормализация модели данных
- •Язык sql
- •Команды sql
- •Команды определения структуры данных (DataDefinitionLanguage–ddl)
- •Команды манипулирования данными (Data Manipulation Language – dml)
- •Команды управления транзакциями (TransactionControlLanguage–tcl)
- •Команды управления доступом (DataControlLanguage–dcl)
- •Работа с командами sql
- •Ключевое слово distinct
- •Секция from, логическое связывание таблиц
- •Секция where
- •Секция orderby
- •Групповые функции
- •Секция group by
- •Секция having
- •Изменение данных
- •Команда insert
- •Команда delete
- •Команда update
- •Определение структуры данных Команда createtable
- •Команда droptable
- •П риложение5
- •П риложение 6
- •П риложение7 журнал сообщений (logger)
- •П риложение 8
- •Портлеты
П риложение7 журнал сообщений (logger)
В процессе функционирования сложных приложений необходимо вести журнал сообщений и ошибок, чтобы была возможность отследить время входа и выхода пользователя из системы, возникновение исключительных ситуаций и т.д. Существуют различные API регистрации сообщений и ошибок. В практическом программировании для этих целей применяется API Log4j, разработанный в рамках проекта Jakarta Apache.
API Log4j – это инструмент для формирования журнала сообщений (отладочных, информационных, сообщений об ошибках). API Log4j можно загрузить по адресу: http://logging.apache.org/log4j/. Перед использованием необходимо зарегистрировать загруженную библиотеку log4j-1.2.13.jar в приложении.
Log4j состоит из трех элементов:
регистрирующего (logger);
направляющего вывод (appender);
форматирующего (layout).
Таким образом logger регистрирует и направляет вывод события в пункт назначения, определяемый элементом appender, в формате, заданном элементом layout.
В стандартной библиотеке java.util.logging также существует возможность журналирования событий. Однако функциональность классов этого пакета несколько уже, чем у классов проекта Log4j, поэтому профессиональные программисты предпочитают использовать последний.
Logger
Основным элементом API регистрации событий и ошибок является регистратор Logger, который управляет регистрацией сообщений. Вывод регистратора может быть направлен на консоль, в файл, базу данных, GUI-компонент или сокет. Это компонент приложения, принимающий и выполняющий запросы на запись в регистрационный журнал.
Каждый класс приложения может иметь свой собственный logger или быть прикреплен к общему для всего приложения. Регистраторы образуют иерархию, как и пакеты Java. Регистратор может быть создан или получен с помощью статического метода getLogger(String name), где name – имя пакета. В вершине иерархии находится корневой регистратор. Он всегда существует и у него нет имени. Он может быть получен статическим методом getRootLogger().
У каждого регистратора есть уровень сообщения по возрастанию (TRACE, DEBUG, INFO, WARN, ERROR, FATAL), который управляет выводом сообщений. Для вывода сообщений конкретного уровня используются методы debug(), info(), warn(), error(), fatal(). Чтобы вывести информацию о возникшем исключении в качестве второго параметра, в вышеперечисленные методы нужно передать объект класса, производного от Throwable. Для вывода сообщения необходимо, чтобы уровень выводимого сообщения был не ниже, чем уровень регистратора (TRACE < DEBUG < INFO < WARN < ERROR < FATAL), т. е. если уровень регистратора INFO, то вызов logger.debug(“message”) не даст никакого эффекта, т. к. DEBUG < INFO. Уровень регистратора можно указать с помощью метода setLevel(Level level), который принимает объект класса Level, содержащий одноименные константы для каждого уровня. Если уровень регистратора не указывается, то наследуется уровень от его родителя. Уровень корневого регистратора DEBUG.
Существуют следующие методы для вывода сообщений:
log(Priority priority, Object message, Throwable t) –выводит сообщения указанного уровня с информацией об исключительной ситуации t.
log(Priority priority, Object message) – выводит сообщения указанного уровня.
Appender и Layout
Вывод регистратора может быть направлен в различные места назначения. Каждому из них соответствует класс, реализующий интерфейс Appender. С помощью метода addAppender(Appender newAppender) класса Logger можно добавить Apeender к регистратору. Один регистратор может иметь несколько элементов Appender. Вывод на консоль осуществляется с помощью класса ConsoleAppender. Класс FileAppender используется для вывода сообщений в файл. Для установки файла, в который будет выполняться вывод, нужно передать имя файла в конструктор FileAppender(Layout layout, String filename) или метод setFile(String file). По умолчанию любые сообщения, записанные в файл, будут добавляться к уже имеющимся. Изменить это можно с помощью конструктора FileAppender(Layout layout, String filename, boolean append) сбросив флаг append или с помощью метода setAppend(boolean append).
Кроме того, вывод в базу данных можно произвести с помощью класса JDBCAppender, в журнал событий ОС – NTEventLogAppender, на SMTP-сервер – SMTPAppender, на удаленный сервер – SocketAppender.
Любой вывод, сделанный в регистраторе, будет направлен всем его предкам. Чтобы этого избежать, в регистраторе следует установить флаг аддитивности с помощью метода setAdditivity(boolean additive). В этом случае вывод будет направлен всем его предкам вплоть до регистратора с установленным флагом аддитивности.
Вывод регистратора может иметь различный формат. Каждый формат представлен классом, производным от Layout. Все методы класса Layout предназначены только для создания подклассов. В библиотеке определены следующие:
HTMLLayout – вывод в HTML-формате;
XMLLayout – вывод в XML-формате;
SimpleLayout – вывод в простом текстовом формате.
Более информативен вывод в XML-формате.
Установить Layout для FileAppender или ConsoleAppender можно с помощью метода setLayout(Layout layout) или передать его в вышеперечисленные конструкторы этих классов.
В приведенном ниже примере производятся регистрация и вывод как обычных информационных сообщений о выполненных действиях, так и сообщений о возникающих ошибках (попытке вычисления факториала отрицательного числа).
/* пример # 1: регистратор ошибок : Demo Log.java */
package app6;
import org.apache.log4j.Logger;
import org.apache.log4j.FileAppender;
import org.apache.log4j.SimpleLayout;
import org.apache.log4j.Level;
import java.io.IOException;
public class DemoLog {
static Logger logger = Logger.getLogger(DemoLog.class);
public static void main(String[] args) {
try {
//возможна и программная настройка
factorial(9);
factorial(-3);
} catch (IllegalArgumentException e) {
//вывод сообщения уровня ERROR
logger.error("negative argument", e);
}
}
public static int factorial(int n) {
if (n < 0)
throw new IllegalArgumentException(
"argument " + n +" less then zero");
//вывод сообщения уровня DEBUG
logger.debug("Argument n is " + n);
int result = 1;
for (int i = n; i >= 1; i--)
result *= i;
//вывод сообщения уровня INFO
logger.info("Result is " + result);
return result;
}
}
При этом в корне проекта должен находиться конфигурационный файл "log4j.xml" со следующим содержимым:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="TxtAppender" class="org.apache.log4j.FileAppender">
<param name="File" value="log.txt" />
<layout class="org.apache.log4j.SimpleLayout"/>
</appender>
<logger name="app6">
<level value="debug" />
</logger>
<root>
<appender-ref ref="TxtAppender" />
</root>
</log4j:configuration>
Вывод регистратора "app6.DemoLog", в файл log.txt будет следующим:
DEBUG - Argument n is 9
INFO - Result is 362880
ERROR - negative argument java.lang.IllegalArgumentException: argument -3 less then zero
at app6.DemoLog.factorial(DemoLog.java:35)
at app6.DemoLog.main(DemoLog.java:27)
Возможна также и программная настройка логгирования. Тогда в код программы необходимо добавить следующее:
FileAppender appender =
new FileAppender(
new SimpleLayout(), "log.txt");
logger.addAppender(appender);
logger.setLevel(Level.DEBUG);
Для вывода на консоль и в XML необходимо добавить следующее в конфигурационный файл:
<appender name="ConsAppender" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.SimpleLayout"/>
</appender>
<appender name="XMLAppender" class="org.apache.log4j.FileAppender">
<param name="File" value="log.xml" />
<layout class="org.apache.log4j.xml.XMLLayout"/>
</appender>
<root>
<appender-ref ref="ConsAppender" />
<appender-ref ref="XMLAppender" />
</root>
Или программно:
ConsoleAppender appender2 =
new ConsoleAppender(new SimpleLayout());
FileAppender appender3 =
new FileAppender(new XMLLayout(), "log.xml");
logger.addAppender(appender2);
logger.addAppender(appender3);
В классе Logger объявлены методы, реагирующие на соответствующие события, а именно: fine(), info(), warning(), log(), throwing() и др.
В приведенном примере запись в файл log.xml производится в зависимости от значения остатка после деления.
/* пример # 2: стандартный регистратор ошибок : StandartDemoLog.java */
package app6;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level
import java.util.logging.Logger;
public class StandartDemoLog {
static Logger log = Logger.getLogger("app6");
public static void main(String[] args)
throws SecurityException, IOException {
/*инициализация и назначение для вывода логов простого файла, который по умолчанию использует XMLFormatter, то есть в файле информация будет сохраняться в виде XML */
FileHandler fh = new FileHandler("log.xml");
log.addHandler(fh);
log.setLevel(Level.WARNING);//установка уровня сообщений
int arr[] = { 5, 6, 1, -4 };
for (int i = 0; i < arr.length; i++) {
int j = arr[i] % 3;
switch (j) {
case 0:
log.fine(arr[i] + "%3 = 0");
break;
case 1:
log.info(arr[i] + "%3 = 1");
break;
case 2:
log.warning(arr[i] + "%3 = 2");
break;
default:
log.severe(arr[i] + "%3 < 0");
}
}
}
}
В результате на консоль будет выведено:
17.03.2006 15:39:03 app6.DemoLog main
WARNING: 5%3 = 2
17.03.2006 15:39:03 app6.DemoLog main
INFO: 1%3 = 1
17.03.2006 15:39:03 app6.DemoLog main
SEVERE: -4%3 < 0
В файле log.xml та же информация будет сохранена в виде
<?xml version="1.0" encoding="windows-1251"
standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2006-03-17T15:39:03</date>
<millis>1142602743635</millis>
<sequence>0</sequence>
<logger>app6</logger>
<level>WARNING</level>
<class>app6.DemoLog</class>
<method>main</method>
<thread>10</thread>
<message>5%3 = 2</message>
</record>
<record>
<date>2006-03-17T15:39:03</date>
<millis>1142602743736</millis>
<sequence>1</sequence>
<logger>app6</logger>
<level>INFO</level>
<class>app6.DemoLog</class>
<method>main</method>
<thread>10</thread>
<message>1%3 = 1</message>
</record>
<record>
<date>2006-03-17T15:39:03</date>
<millis>1142602743736</millis>
<sequence>2</sequence>
<logger>app6</logger>
<level>SEVERE</level>
<class>app6.DemoLog</class>
<method>main</method>
<thread>10</thread>
<message>-4%3 < 0</message>
</record>
</log>
В несложных учебных проектах проще использовать стандартную библиотеку.
JUnit
Технология JUnit предлагает сделать более тесной связь между разработкой кода и его тестированием. В Java существует возможность проверить корректность работы класса, не прибегая к пробному выводу при отладке программы.
Технология JUnit позволяет вне класса создавать тесты, при выполнении которых произойдет корректное завершение программы в результате неправильной ее работы. Кроме того, будет создано сообщение о возникшей ошибке. Если же результат работы теста не выявит ошибок, то программа продолжит её выполнение.
Тесты создаются в процессе разработки в случае, когда требуется расширить функциональность системы. Разработка завершается, когда тест пройдет успешно.
В процессе отладки тесты создаются, если в коде обнаруживается ошибка. Затем отладку следует продолжить до момента корректной отработки теста.
Компиляция и запуск
Загрузить JUnit с сервера www.junit.org
Распаковать загруженный архив
Добавить в переменную окружения CLASSPATH CLASSPATH=%CLASSPATH%;%JUNIT_HOME%\junit.jar
Для консольного режима запуск выполнить: java junit.textui.TestRunner junit.samples.AllTests
Пусть класс ChangedName манипулирует именами файлов и генерирует имя файла с определенным расширением на основании заданного имени. Тестируемый класс будет содержать метод String rename(String ext), где параметр ext – новое расширение файла. Также класс будет иметь конструктор, принимающий имя изменяемого файла.
/*пример # 3: генерация имени файла с заданным расширением:
ChangedName.java */
package app6;
public class ChangedName {
private String name;
// реализация
public ChangedName(String name){
this.name = name;
}
public String rename(String ext) {
String old = name;
int dot_pos = old.indexOf('.');
if (dot_pos > 0)
old = old.substring(0, dot_pos);
return old + "." + ext;
}
}
Далее создан тест для метода rename() с учетом того, что он должен задавать имени файла новое расширение.
/*пример # 4: тестирование метода rename() класса ChangedName:
ChangedNameTest.java */
package app6;
public class ChangedNameTest extends TestCase {
// метод-тестировщик должен называться testИмя, где Имя – это имя тестируемого метода
public void testRename(){
ChangedName changed = new ChangedName("report");
/*метод проверяет, равны ли ожидаемая и полученная строки, и если результатом будет false, то тест завершит работу приложения*/
assertEquals("report.txt", changed.rename("txt"));
}
}
/* пример # 5: класс, который проверяет, является ли одно число делителем другого: Devisor.java*/
package app6;
public class Devisor {
public boolean isDevisor(int num1,int num2){
if((num2!=0)&&(num1%num2==0))return true; //1
// if(num1%num2==0) return true; // 2
else return false;
}
}
Ниже реализован тест, который проверят корректность работы метода isDevisor().
/* пример # 6: тестирование метода isDevisor() класса Devisor:
DevisorTest.java*/
package app6;
import junit.framework.TestCase;
public class DevisorTest extends TestCase {
public void testIsDevisor() {
Devisor obj = new Devisor();
boolean result1 = obj.IsDevisor(2,1);
boolean result2 = obj.IsDevisor(1,0);
assertEquals(true, result1); // test1
/*test1 проверяет, действительно ли результат работы метода для чисел 2 и 1 равен true. Если это верно, то выполнится следующий тест, если нет, то приложение завершит работу, а тестировщик сообщит об ошибке.*/
assertEquals(false, result2);// test2
}
}
В данном случае программа верна. Если же закомментировать строку 1 и убрать комментарий со строки 2 в классе Devisor, то test1 выполнится корректно, а test2 завершит работу приложения и выдаст сообщение об оши- бке из-за генерации при работе метода необработанного исключения ArithmeticException.
/*пример # 7: класс позволяет считывать информацию из заданного файла и преобразовывать её в строку: ReadFile.java*/
package app6;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile {
public String fileIntoString(String st) {
String str = "";
try {
FileReader stream = new FileReader(st);
int s;
while ((s = stream.read()) != -1) {
str = str + s;
}
System.out.println(str);
stream.close();
} catch (IOException e) {
System.err.println(e);
}
return str;
}
}
Тест, проверяющий корректную работу этого класса:
/* пример # 8: тестирование класса ReadFile: ReadFileTest.java*/
package app609;
import junit.framework.TestCase;
public class ReadFileTest extends TestCase {
public void testFileIntoString() {
ReadFile obj = new ReadFile();
String st =
obj.fileIntoString("D:\\temp\\test.txt");
assertFalse("".equals(st));
/*если файл не существует или не пуст, то программа завершит работу с сообщением об ошибке*/
}
}
В простом пользовательском классе StringConCat реализован метод concat(String s1, String s2), который объединяет две строки.
/*пример # 9: тестируемый класс: StringConCat.java*/
package app609;
public class StringConCat {
// реализация
public String concat(String st1, String st2) {
String str = st1 + st2;
return str;
}
}
Тест, проверяющий корректность работы этого метода:
/* пример # 10: тестирование метода concat() класса StringConCat:
StringConCatTest.java*/
package app6;
import junit.framework.TestCase;
public class StringConCatTest extends TestCase {
public void testConcat(){
StringConCat obj = new StringConCat();
String st = obj.concat("Java", "2");
assertEquals("Java2", st);
}
}
Последняя версия JUnit полностью основана на аннотациях и в явном виде не использует тип TestCase.