Выбрать главу

• перед тем как писать любой фрагмент кода, создайте автоматизированный тест, который поначалу будет терпеть неудачу;

• устраните дублирование.

Как конкретно следовать этим правилам, какие существуют в данной области нюансы и какова область применимости этих способов – все это составляет тему книги, которую вы сейчас читаете. Вначале мы рассмотрим объект, созданный Уордом в момент вдохновения, – мультивалютные деньги (multi-currency money).

Часть I

На примере денег

Мы займемся реализацией примера, разрабатывая код полностью на основе тестирования (кроме случаев, когда в учебных целях будут допускаться преднамеренные ошибки). Моя цель – дать вам почувствовать ритм разработки через тестирование (TDD). Кратко можно сказать, что TDD заключается в следующем:

• Быстро создать новый тест.

• Запустить все тесты и убедиться, что новый тест терпит неудачу.

• Внести небольшие изменения.

• Снова запустить все тесты и убедиться, что на этот раз все тесты выполнились успешно.

• Провести рефакторинг для устранения дублирования.

Кроме того, придется найти ответы на следующие вопросы:

• Как добиться того, чтобы каждый тест охватывал небольшое приращение функциональности?

• Как и за счет каких небольших и, наверное, неуклюжих изменений обеспечить успешное прохождение новых тестов?

• Как часто следует запускать тесты?

• Из какого количества микроскопических шагов должен состоять рефакторинг?

1. Мультивалютные деньги

Вначале мы рассмотрим объект, созданный Уордом для системы WyCash, – мультивалютные деньги (см. «Введение»). Допустим, у нас есть отчет вроде этого.

Добавив различные валюты, получим мультивалютный отчет.

Также необходимо указать курсы обмена.

$5 + 1 °CHF = $10, если курс обмена 2:1

$5 * 2 = $10

Что нам понадобится, чтобы сгенерировать такой отчет? Или, другими словами, какой набор успешно выполняющихся тестов сможет гарантировать, что созданный код правильно генерирует отчет? Нам понадобится:

• выполнять сложение величин в двух различных валютах и конвертировать результат с учетом указанного курса обмена;

• выполнять умножение величин в валюте (стоимость одной акции) на количество акций, результатом этой операции должна быть величина в валюте.

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

Как видно из нашего списка задач, сначала мы займемся умножением. Итак, какой объект понадобится нам в первую очередь? Вопрос с подвохом. Мы начнем не с объектов, а с тестов. (Мне приходится постоянно напоминать себе об этом, поэтому я просто притворюсь, что вы так же забывчивы, как и я.)

Попробуем снова. Итак, какой тест нужен нам в первую очередь? Если исходить из списка задач, первый тест представляется довольно сложным. Попробуем начать с малого – умножение, – сложно ли его реализовать? Займемся им для начала.

Когда мы пишем тест, мы воображаем, что у нашей операции идеальный интерфейс. Попробуем представить, как будет выглядеть операция снаружи. Конечно, наши представления не всегда будут находить воплощение, но в любом случае стоит начать с наилучшего возможного программного интерфейса (API) и при необходимости вернуться назад, чем сразу делать вещи сложными, уродливыми и «реалистичными».

Простой пример умножения[4]:

public void testMultiplication() {

Dollar five = new Dollar(5);

five.times(2);

assertEquals(10, five.amount);

}

(Знаю, знаю: публичные поля, побочные эффекты, целые числа для денежных величин и все такое. Маленькие шаги – помните? Мы отметим, что где-то есть душок[5], и продолжим дальше. У нас есть тест, который не выполняется, и мы хотим как можно скорее увидеть зеленую полоску[6].)

$5 + 1 °CHF = $10, если курс обмена 2:1

$5 * 2 = $10

Сделать переменную amount закрытым членом класса

Побочные эффекты в классе Dollar?

Округление денежных величин?

вернуться

4

Название метода times() можно перевести на русский как «умножить на». – Примеч. пер.

вернуться

5

Код с душком (code that smells) – распространенная в XP метафора, означающая плохой код (содержащий дублирование). – Примеч. пер.

вернуться

6

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