Вопреки распространенному мнению, TDD - это не процесс тестирования. Это процесс проектирования. Это надежный способ интерактивного проектирования программных компонентов, по одному за раз, за ​​счет того, что поведение отдельного компонента заранее задано с помощью модульных тестов.

В моем последнем рассказе я подробно обсуждал образ мышления, который следует иметь перед применением TDD. Вы можете прочитать его по ссылке ниже.

Образ мышления, лежащий в основе разработки через тестирование (TDD)

В этой истории мы увидим, как выглядит базовая реализация TDD. Обратите внимание, что я не буду описывать мельчайшие подробности модульного тестирования, которое включает в себя такие концепции, как настройка тестов, имитация, различные типы утверждений и т. Д. Я постараюсь изобразить идею как язык программирования и фреймворк модульного тестирования, насколько это возможно. Однако в своем примере я буду использовать JavaScript.

Допустим, нам нужно написать функцию, которая будет принимать n в качестве параметра и возвращать n-е число Фибоначчи в ряду Фибоначчи. Можем ли мы сделать это, используя подход TDD? Давай попробуем.

Для начала напишем наш первый тест.

/FibonacciSpec.js
it('should return 0 as the 1st Fibonacci number', () => {
 expect(getNthFibonacci(1)).toBe(0);
});

Теперь, если мы запустим вышеуказанный тест, мы получим следующий результат.

Fibonacci should return 0 as the 1st Fibonacci number
ReferenceError: getNthFibonacci is not defined

Очевидно, мы получим ошибку, поскольку мы еще не определили какой-либо метод getNthFibonacci. Напишем метод.

/Fibonacci.js
function getNthFibonacci (n) {
 
}

Теперь, если мы запустим тест, мы получим -

Fibonacci should return 0 as the 1st Fibonacci number
Expected undefined to be 0.

Наш метод getNthFibonacci возвращает неверное значение. На самом деле он ничего не возвращает. Давайте исправим это и запустим тест.

/Fibonacci.js
function getNthFibonacci (n) {
 return 0; 
}
Fibonacci
 should return 0 as the 1st Fibonacci number

Ура !!! Теперь испытание прошло. Напишем второй тест и запустим его.

/FibonacciSpec.js
it(‘should return 1 as the 2nd Fibonacci number’, () => {
 expect(getNthFibonacci(2)).toBe(1);
});
Fibonacci should return 1 as the 2nd Fibonacci number
Expected 0 to be 1.

Оппс, тест снова не удался. Давайте внесем изменения в наш код, чтобы пройти этот тест, и снова запустим его.

/Fibonacci.js
function getNthFibonacci (n) {
 return n — 1; 
}
Fibonacci
 should return 1 as the 2nd Fibonacci number

Здорово!!! Наш 2-й тест пройден.

Теперь давайте напишем наш третий тест и запустим его.

/FibonacciSpec.js
it(‘should return 1 as the 3rd Fibonacci number’, () => {
 expect(getNthFibonacci(3)).toBe(1);
});
Fibonacci should return 1 as the 3rd Fibonacci number
Expected 2 to be 1.

Давайте напишем код, чтобы пройти этот тест.

/Fibonacci.js
function getNthFibonacci (n) {
 if (n > 2) {
 return getNthFibonacci (n — 1) + getNthFibonacci (n — 2);
 }
 return n — 1;
}
Fibonacci
 should return 1 as the 3rd Fibonacci number

Давайте напишем еще один тест, чтобы укрепить нашу логику генерации Фибоначчи, и запустим его.

/FibonacciSpec.js
it(‘should return 8 as the 7th Fibonacci number’, () => {
 expect(getNthFibonacci(7)).toBe(8);
});
Fibonacci
 should return 8 as the 7th Fibonacci number

Похоже, наша логика в порядке. Сейчас хорошее время для рефакторинга. Давайте проведем рефакторинг этого кода, чтобы улучшить его читаемость, и запустим все тесты.

/Fibonacci.js
function getNthFibonacci (n) {
 return (n === 1 || n === 2) ? n — 1
  : getNthFibonacci (n — 1) + getNthFibonacci (n — 2);
}
Fibonacci
 should return 0 as the 1st Fibonacci number
 should return 1 as the 2nd Fibonacci number
 should return 1 as the 3rd Fibonacci number
 should return 8 as the 7th Fibonacci number

Выглядит отлично. Однако мы хотим, чтобы наш метод getNthFibonacci выдавал ошибку, если ’n’ равно 0 или отрицательному числу. Напишем для этого несколько тестов и запустим их.

/FibonacciSpec.js
it(‘should throw an error when n is 0’, () => {
 expect(() => getNthFibonacci(0)).toThrowError(‘n cannot be 0 or a negative number’);
});
it(‘should throw an error when n is a negative number’, () => {
 expect(() => getNthFibonacci(-3)).toThrowError(‘n cannot be 0 or a negative number’);
});
Fibonacci should throw an error when n is 0
RangeError: Maximum call stack size exceeded.
Fibonacci should throw an error when n is a negative number
RangeError: Maximum call stack size exceeded.

Нам нужно написать код для обработки этих ситуаций.

/Fibonacci.js
function getNthFibonacci (n) {
 if (n <= 0) throw new Error(‘n cannot be 0 or a negative number’)
 
 return (n === 1 || n === 2) ? n — 1
 : getNthFibonacci (n — 1) + getNthFibonacci (n — 2);
}
Fibonacci
 should return 0 as the 1st Fibonacci number
 should return 1 as the 2nd Fibonacci number
 should return 1 as the 3rd Fibonacci number
 should return 8 as the 7th Fibonacci number
 should throw an error when n is 0
 should throw an error when n is a negative number

Чудесный!!! Похоже, у нас есть надежный метод getNthFibonacci с конкретным набором тестов. Мы только что закончили разработку простой функции генерации чисел Фибоначчи с использованием подхода TDD.

Вот и все. Надеюсь, вы получили хорошую идею и, что более важно, преодолели свой страх перед TDD после завершения этой серии. Итак, начните использовать TDD, пока не поздно, и не забывайте получать удовольствие. Мир 👍