странное: при выполнении операции с объектом Dollar изменяется сам
объект. Хотело сь бы написать так:
public void testMultiplication() {
Dollar five = new Dollar(5);
five.times(2);
assertEquals(10, five.amount);
five.times(3);
assertEquals(15, five.amount);
}
Я не могу пред ставить про стого спо соба, который заставит этот
тест выполняться. По сле первого вызова метод а times() пять уже больше
не пять – на самом д еле это уже д есять. Если же метод times() буд ет
возвращать
новый объект, тогд а мы сможем умножать наши исход ные
пять баксов хоть целый д ень, и они не изменятся. Для реализации этой
ид еи нам потребуется изменить интерфейс объекта Dollar и,
соответственно, изменить тест. Это нормально,
вед ь вполне возможно,
что наши д огад ки о правильном интерфейсе не более правд опод обны,
чем д огад ки о правильной реализации.
public void testMultiplication() {
Dollar five = new Dollar(5);
Dollar product = five.times(2);
assertEquals(10, product.amount);
product = five.times(3);
assertEquals(15, product.amount);
}
Новый тест не буд ет компилироваться, пока мы не изменим
объявление метод а Dollar.times():
Dollar
Dollar times(int multiplier) {
amount *= multiplier;
return null;
}
Теперь тест компилируется, но не работает. И это тоже прогресс!
Чтобы заставить его работать, прид ется
возвращать новый объект
Dollar с правильным значением:
Dollar
Dollar times(int multiplier) {
return new Dollar(amount * multiplier);
}
$5 + 1 °CHF = $10, если курс обмена 2:1
$5 * 2 = $10
Сд елать переменную amount закрытым членом класса
Побочные эффекты в классе Dollar?
Округление д енежных величин?
В главе 1, когд а мы заставляли тест работать, мы начинали с
заготовки и по степенно улучшали код , пока он не стал полноценным.
Теперь мы написали сразу правильную реализацию и молились, пока
выполнялись тесты (д овольно короткие молитвы, честно говоря –
выполнение тестов занимает миллисекунд ы).
Нам повезло, тесты
выполнились успешно, и мы вычеркнули еще од ин пункт.
Мне известны три спо соба быстрого получения зеленого
инд икатора. Вот первые д ва:
• под д елать реализацию, иначе говоря, созд ать заглушку,
возвращающую
константу,
и
по степенно
заменять
константы
переменными д о тех пор, пока не получится настоящий код ;
• использовать очевид ную реализацию – про сто написать сразу
настоящую реализацию.
Используя
TDD на практике, я период ически переключаюсь межд у
д вумя этими спо собами. Когд а все ид ет глад ко и я знаю, что д елать, – я
про сто созд аю од ну за д ругой очевид ные реализации (кажд ый раз
запуская тесты, чтобы убед иться, что решение, очевид ное д ля меня,
также очевид но д ля компьютера). Как только я натыкаюсь на красный
инд икатор, я возвращаюсь к метод ике «под д ельная реализация»,
по сле
чего провожу рефакторинг. Когд а уверенно сть возвращается, я снова
использую метод ику «очевид ная реализация».
Есть еще од на, третья метод ика, «Триангуляция» (Triangulation),
которую мы рассмотрим в главе 3. Под вед ем итоги. Мы выполнили
след ующее:
• сформулировали д ефект проектирования (побочный эффект) в
вид е теста, который потерпел неуд ачу (из-за д ефекта);
• созд али заглушку, обеспечившую быструю компиляцию код а;
• заставили
тест успешно выполняться, написав врод е бы
правильный код .
Преобразование чувства (например, отвращения, вызываемого
побочными эффектами) в тест (например, д вукратное перемножение
од ного и того же объекта Dollar) – обычная практика в TDD. Чем
д ольше я этим занимаюсь, тем
легче эстетические сужд ения
перевод ятся в тесты. В результате мои рассужд ения о проектировании
становятся более интересными. Сначала мы обсужд аем, д олжна ли
система работать
так
или
по-другому
. По сле опред еления правильного
повед ения системы можно поговорить о
наилучшем спо собе его
реализации. Можно сколь угод но д олго рассужд ать об истине и
совершенстве за пивом, но раз мы занимаемся программированием, у нас
есть возможно сть о ставить пустые разговоры и перейти к конкретике.