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




int fib(int n) {

if (n == 0) return 0;

return 1;

}


Дублирование в тестирующем методе начинает действовать мне на нервы. По мере добавления новых тестов, дублирование будет только усугубляться. Давайте попробуем выделить общую структуру операторов assert(), для этого добавим в тест таблицу входных и ожидаемых значений функции fib():


public void testFibonacci() {

int cases[][] = {{0,0},{1,1}};

for (int i = 0; i < cases.length; i++)

assertEquals(cases[i][1], fib(cases[i][0]));

}


Теперь добавление нового теста требует всего шесть нажатий на клавиши и никаких дополнительных строк:

public void testFibonacci() {


int cases[][] = {{0,0},{1,1},{2,1}};

for (int i = 0; i < cases.length; i++)

assertEquals(cases[i][1], fib(cases[i][0]));

}


Как это ни удивительно, но новый тест работает. Это происходит потому, что константа 1 также подходит и для входного значения 2. Переходим к следующему тесту:


public void testFibonacci() {

int cases[][] = {{0,0},{1,1},{2,1},{3,2}};

for (int i = 0; i < cases.length; i++)

assertEquals(cases[i][1], fib(cases[i][0]));

}


Ура! Наконец-то тест не сработал. Воспользуемся прежней стратегией (рассматриваем меньшие входные значения как специальные случаи):


int fib(int n) {

if (n == 0) return 0;

if (n <= 2) return 1;

return 2;

}


Теперь мы готовы обобщить код. Мы написали 2, однако на самом деле мы имели в виду 1 + 1.


int fib(int n) {

if (n == 0) return 0;

if (n <= 2) return 1;

return 1 + 1;

}


Первая единица в сумме – на самом деле fib(n-1):


int fib(int n) {

if (n == 0) return 0;

if (n <= 2) return 1;

return fib(n-1) + 1;

}


Вторая единица в сумме – на самом деле fib(n-2):

int fib(int n) {

if (n == 0) return 0;

if (n <= 2) return 1;

return fib(n-1) + fib(n-2);

}


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


int fib(int n) {

if (n == 0) return 0;

if (n == 1) return 1;

return fib(n-1) + fib(n-2);

}


Это и есть функция вычисления последовательности Фибоначчи, целиком и полностью разработанная в рамках методики TDD.

Послесловие

Мартин Фаулер (Martin Fowler)


Когда рассказываешь о разработке, основанной на тестировании, сложнее всего передать то психическое состояние, в котором находишься, работая в стиле TDD. Я помню, как в ходе проекта C3 мы с Ральфом Битти (Ralph Beattie) работали над реализацией сложного набора условий выплаты. Ральф сформулировал набор соответствующих тестов, после чего мы приступили к реализации этих тестов одного за другим. Процесс был равномерным и неторопливым, из-за этого казалось, что мы работаем медленно. Однако, взглянув назад на проделанную работу, можно было понять, что, несмотря на кажущуюся неторопливость, мы работали очень даже быстро.