1 ...6 7 8 10 11 12 ...82 $5 + 1 °CHF = $10, если курс обмена 2:1
$5 * 2 = $10
Сделать переменную amount закрытым членом класса
Побочные эффекты в классе Dollar?
Округление денежных величин?
Мы получили один рабочий тест, но в процессе заметили нечто странное: при выполнении операции с объектом 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. Чем дольше я этим занимаюсь, тем легче эстетические суждения переводятся в тесты. В результате мои рассуждения о проектировании становятся более интересными. Сначала мы обсуждаем, должна ли система работать так или по-другому . После определения правильного поведения системы можно поговорить о наилучшем способе его реализации. Можно сколь угодно долго рассуждать об истине и совершенстве за пивом, но раз мы занимаемся программированием, у нас есть возможность оставить пустые разговоры и перейти к конкретике.
Если у меня есть целое число и я прибавляю к нему 1, то не предполагаю, что изменится исходное число, – в результате я ожидаю получить новое число. Объекты же обычно ведут себя иначе. К примеру, если у меня есть контракт и я добавлю 1 к его сумме, это будет означать, что сумма контракта должна измениться (да, несомненно, это пример для обсуждения многих интересных законов бизнеса, которые мы здесь рассматривать не будем).
Читать дальше
Конец ознакомительного отрывка
Купить книгу