И снова тест получился длиннее тестируемого кода. (Те, кто достаточно много работал с JUnit, должно быть уже догадались, как решить эту проблему. Остальным я рекомендую прочитать раздел «
Sum
Expression times(int multiplier) {
return new Sum(augend.times(multiplier), addend.times(multiplier));
}
В предыдущей главе мы изменили тип переменных augend и addend на Expression, поэтому теперь, чтобы скомпилировать код, нам необходимо добавить в интерфейс Expression метод times():
Expression
Expression times(int multiplier);
При этом нам следует изменить режим видимости методов Money.times() и Sum.times() (они должны стать общедоступными):
Sum
public Expression times(int multiplier) {
return new Sum(augend.times(multiplier), addend.times(multiplier));
}
Money
public Expression times(int multiplier) {
return new Money(amount * multiplier, currency);
}
Операция $5 + $5 возвращает объект Money
Все заработало.
Осталось провести эксперимент для случая, когда в результате выполнения операции $5 + $5 получается объект Money. Вот соответствующий тест:
public void testPlusSameCurrencyReturnsMoney() {
Expression sum = Money.dollar(1). plus(Money.dollar(1));
assertTrue(sum instanceof Money);
}
Тест выглядит несколько неопрятно, так как тестирует внутреннюю реализацию, а не внешнее поведение объектов. Однако он принуждает нас внести в программу изменения, которые нам необходимы, и, в конце концов, это всего лишь эксперимент. Вот код, который мы должны модифицировать, чтобы заставить тест работать:
Money
public Expression plus(Expression addend) {
return new Sum(this, addend);
}
Операция $5 + $5 возвращает объект Money
Не существует очевидного и ясного способа проверить валюту аргумента, если этот аргумент является объектом класса Money (по крайней мере, я не могу найти такого способа, однако вы можете над этим подумать). Эксперимент окончился неудачей, мы удаляем тест (который нам все равно не нравился).
Подводим итог. Мы
• написали тест так, чтобы его смысл легко был понят другими программистами, которые в будущем будут читать разработанный нами код;
• наметили эксперимент, призванный сравнить эффективность TDD по отношению к обычному стилю программирования, используемому вами на текущий момент;
• снова столкнулись с необходимостью изменения множества объявлений в разрабатываемом коде и снова воспользовались услугами компилятора, чтобы исправить все неточности;
• попробовали провести быстрый эксперимент, однако отказались от идеи, так как она не сработала, и уничтожили соответствующий тест.
17. Ретроспектива денежного примера
Давайте еще раз окинем взглядом пример реализации мультивалютных вычислений и попробуем оценить использованный нами подход и полученные результаты. Вот несколько тезисов, которых хотелось бы коснуться:
Можно ли считать код завершенным? Нет. Методы Sum.plus() и Money.plus() во многом дублируют друг друга. Если мы преобразуем интерфейс Expression в класс (не совсем обычное преобразование – чаще классы становятся интерфейсами), мы получим возможность переместить общий код в единый общий метод.
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии