Экстремальное программирование. Разработка через тестирование | страница 32




Franc

Money times(int multiplier) {

return new Money (amount * multiplier, currency);

}


В ответ компилятор сообщил, что Money должен быть конкретным (не абстрактным) классом:


Money

class Money

Money times(int amount) {

return null;

}


Получаем красную полоску и сообщение об ошибке: «expected: but was:». Не очень-то информативно. Не так информативно, как нам хотелось бы. Чтобы получить более осмысленное сообщение об ошибке, добавим метод toString():


Money

public String toString() {

return amount + " " + currency;

}


О, ужас! Код без тестов?! Допустимо ли такое? Конечно же, прежде чем писать код метода toString, мы должны были написать соответствующий тест, однако

• мы увидим результаты работы этого метода на экране;

• метод toString() используется только для отладки, поэтому риск, связанный с потенциальными ошибками, невелик;

• перед нами красная полоса, а мы предпочитаем не писать новых тестов, пока не избавимся от красной полосы.

Обстоятельства приняты к сведению.

Теперь сообщение об ошибке изменилось: "expected:<1 °CHF> but was:<1 °CHF>". Выглядит осмысленней, однако сбивает с толку. В двух объектах хранятся одни и те же данные, однако при этом объекты не считаются равными. Проблема кроется в реализации метода equals():


Money

public boolean equals(Object object) {

Money money = (Money) object;

return amount == money.amount

&& getClass(). equals(money.getClass());

}


В данном случае происходит сравнение имен классов, в то время как логичнее сравнивать идентификаторы валют.

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

В данном случае мы будем действовать консервативно. (Иногда я плюю на все и пишу тест, не обращая внимания на красную полосу, однако я поступаю так, только когда дети уже спят.)


Franc

Money times(int multiplier) {

return new Franc (amount * multiplier, currency);

}


Перед нами снова зеленая полоса. Мы попали в ситуацию, когда объект Franc(10,"CHF") не равен объекту Money(10,"CHF"), хотя нам хотелось бы, чтобы эти объекты были равны. Превращаем наше желание в тест: