Вопреки распространенному мнению, 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, пока не поздно, и не забывайте получать удовольствие. Мир 👍