Экстремальное программирование. Разработка через тестирование | страница 103
/* Извлечь из пространства кортежей */
/** Извлечение несуществующего элемента **/
/** Извлечение существующего элемента **/
/** Извлечение нескольких элементов **/
/* Читать из пространства кортежей */
Как правило, мне хватает двух-трех уровней комментариев. Я не могу представить ситуацию, в которой мне могло бы потребоваться больше уровней. Список тезисов становится документацией контракта для тестируемого класса. Приведенные здесь примеры, конечно же, сокращены, однако в языках программирования, поддерживающих контракты, тезисы могли бы быть более конкретными. (Я не использую какие-либо добавления к Java, обеспечивающие автоматизацию в стиле Eiffel.)
Сразу же после самого низкого уровня комментариев располагается исходный код теста.
Как можно протестировать ожидаемое исключение? Перехватите исключение и игнорируйте его, тест должен терпеть неудачу только в случае, если исключение не сгенерировано.
Предположим, что мы пишем код, осуществляющий поиск значения. Если значение не обнаружено, мы хотим сгенерировать исключение. Тестирование механизма поиска выполняется относительно просто:
public void testRate() {
exchange.addRate("USD", "GBP", 2);
int rate = exchange.findRate("USD", "GBP");
assertEquals(2, rate);
}
Тестирование исключения может оказаться неочевидным. Вот как мы это делаем:
public void testMissingRate() {
try {
exchange.findRate("USD", "GBP");
fail();
} catch (IllegalArgumentException expected) {
}
}
Если метод findRate() не генерирует исключения, произойдет обращение к методу fail() – это метод xUnit, который докладывает о том, что тест потерпел неудачу. Обратите внимание, что мы перехватываем только то исключение, которое должно быть сгенерировано методом findRate(). Благодаря этому, если будет сгенерировано какое-либо другое (неожиданное для нас) исключение (включая сбой метода assert), мы узнаем об этом.
Как можно запустить все тесты вместе? Создайте тестовый набор, включающий в себя все имеющиеся тестовые наборы, – один для каждого пакета (package) и один, объединяющий в себе все тесты пакетов для всего приложения.
Предположим, вы добавили подкласс класса TestCase и в этот подкласс вы добавили тестовый метод. В следующий раз, когда будут выполняться все тесты, добавленный вами тестовый метод также должен быть выполнен. (Во мне опять проснулась привычка действовать в стиле TDD – должно быть, вы заметили, что предыдущее предложение – это эскиз теста, который я, наверное, написал бы, если бы не был занят работой над данной книгой.) К сожалению, в большинстве реализаций xUnit, равно как и в большинстве IDE, не поддерживается стандартный механизм запуска абсолютно всех тестов, поэтому в каждом пакете необходимо определить класс AllTests, который реализует статический метод suite(), возвращающий объект класса TestSuite. Вот класс AllTests для «денежного» примера: