RANUX 12.12.2010 12:14
Python — Урок 1.1 TDD для начинающих на Python
Представляю вашему вниманию первую часть первого урока посвящённую разработке через тестирование. Надеюсь будет полезно:) Старался написать максимально простым языком:) Комментарии приветствуются.Добро пожаловать на серию уроков по Test Driven Development. Для тех кто ещё не знает что такое TDD: Разрабо?тка че?рез тести?рование (англ. test-driven development) — техника программирования, при которой модульные тесты для программы или её фрагмента пишутся до самой программы и, по существу, управляют её разработкой. Основная идея - реализовать правильно работающий функционал, обеспечить возможность повторного использования и простого изменения структуры исходного кода, при этом не изменяя его поведения (рефакторинг)
Давайте в начале рассмотрим из каких
шагов состоит TDD:
Красный. Подготавливаем файл с тестом,
создаём не работающий тест
Зелёный. Заставляем тест сработать
Рефакторинг Удаляем дублирование
Помимо этих основных шагов я применяю в начале нулевой шаг - «исследование и хакинг» в случае, когда я с трудом представляю, как мне пройти последующие 3-и шага. Давайте пройдёмся по этим шагам на примере реализации простой задачи, например вычисления факториала.
Исследование и хакинг. Что нам известно о
факториале?
Давайте разберём пример:
n! = 1 * 2 * 3 * … * n
0! = 1 1! = 1 2! = 2 3! = 6 4! = 24 и так далее
Предположим, что я впервые открыл интерпретатор python и пока с трудом представляю себе как этом можно
реализовать. :) Попробуем поэксперементировать и немного похакать)
Но для начала, составим список того, что нам понадобиться сделать.
Умножение
Функции
Условные операторы
Аргументы функции
Рекурсия
Запускаем консоль и заходим в python.
>>> 2 * 3
6
Умножение
Функции
Условные операторы
Аргументы функции
Рекурсия
С умножением всё ясно. Теперь попробуем написать какую-нибудь простую функцию:
1 |
|
Отлично, наша функция отработала. Не забываем про отступы в функциях, те перед print "hello" у меня стоят два пробела.
Посмотрим как функция будет возвращать наше значение:
1 |
|
С этим разобрались.
Умножение
Функции
Условные операторы
Аргументы функции
Рекурсия
Теперь посмотрим как работают условные операторы и аргументы функции:
1 |
>>> def f(flag):
|
Если наш флаг присутствует, то возвращаем True, в противном случае False.
Умножение
Функции
Условные операторы
Аргументы функции
Рекурсия
Что же такое рекурсия. Рекурсия — это функция вызывающая сама себя. Давайте разберёмся:
1 |
>>> def f(n):
|
В месте return f(n-1) функция будет вызывать сама себя, но n при этом будет уменьшаться на единицу. Конструкция print "n: %s" % n
вставляет n в строку и форматирует его как строковое значение.
Умножение
Функции
Условные операторы
Аргументы функции
Рекурсия
Достаточно поэкспериментировав, мы готовы перейти к разработке через тестирование нашей функции факториала :)
Что-бы упростить задачу, воспользуемся
doctest-ами.
Снова составим список того, что нам надо
сделать:
Эксперимент с doctest
Вычисление факториала
Созадём файл factor.py содержащий:
1 |
|
Попробуйте его запустить из консоли: python
factor.py
Отлично, пока что у нас нечего не выводиться, но файл выполнился.
Попробуем написать тест для простой функции. Doctest записывается в документации к функции, те сразу после названия функции.
Смотрим пример:
1 |
def f(a, b):
|
Оператор pass означает, что делать нечего не надо. Попробуем запустить: python factor.py
В результате видим:
**********************************************************************
File "factor.py", line 11, in __main__.f
Failed example:
f(1,2)
Expected:
3
Got nothing
**********************************************************************
1 items had failures:
1 of 1 in __main__.f
***Test Failed*** 1 failures.
Отлично, мы проделали первый шаг TDD - «Красный». Приступим к зелёному .
1 |
|
Запускаем и видим, что наша функция прошла тест, второй шаг «Зелёный» вроде пройден, но что если мы попробуем вызвать
f(2, 3). Изменим функцию и посмотрим результат:
1 |
|
Запускаем python factor.py
**********************************************************************
File "factor.py", line 13, in __main__.f
Failed example:
f(2,3)
Expected:
5
Got:
3
**********************************************************************
1 items had failures:
1 of 2 in __main__.f
***Test Failed*** 1 failures
Что и следовало ожидать, мы хотим 2 + 3 = 5, но получили 3. Теперь у нас достаточно тестов чтобы реализовать нашу функцию. Приступим:
1 |
|
Запускаем python factor.py и видим, что тесты прошли. Отлично. Мы написали первую функию в рамках TDD и разобрались с doctest-ом.
На этом я заканчиваю первую часть первого урока. Во второй части разберёмся как реализовать функцию вычисления
факториала.
Эксперимент с doctest
Вычисление факториала
Домашнее задание
Напишите функцию разницы. Тест для функции:
1 |
|
Попробуйте написать функцию вычисления факториала используя подход, который я описал для функции сложения. Если не получиться, то попробуйте реализовать как сможете.
вместо pass и подобных загушек рекомендую использовать честные raise NotImplementedError
также, многие редакторы подсвечивают строки типа TODO и FIXME
также, многие редакторы подсвечивают строки типа TODO и FIXME
Жду продолжения, своими идеями поделюсь когда будут затрагиваться более продвинутые аспекты.
спасибо, плюсанул, но...
если пост ссылка, то зачем копировать всё?
и если уж скопировал, то кат всеравно раньше ставь.
если пост ссылка, то зачем копировать всё?
и если уж скопировал, то кат всеравно раньше ставь.
вот так отлично, я бы даже перед самим катом добавил бы:
«продолжение внутри» или «кто заинтересовался, продолжение под катом»
«продолжение внутри» или «кто заинтересовался, продолжение под катом»
Похоже что все вышеописанное - это часть стандартной документации unittest.
Дело в том, что полным новичкам не нужно TDD, а более продвинутые уже все это и так знают.
Я бы посоветовал вам написать:
- про mock библиотеки
- про nosetest, как запускать его с django
- про инструменты BDD
- про интеграцию code coverage с nosetest
- рассказать о том, какин нужно писать тесты, а какие не нужно (антипаттерны).
С этими вещами приходится сталкиваться в реальной разработке и мне кажется, что статья с описанием подобных вещей была бы полезнее.
Дело в том, что полным новичкам не нужно TDD, а более продвинутые уже все это и так знают.
Я бы посоветовал вам написать:
- про mock библиотеки
- про nosetest, как запускать его с django
- про инструменты BDD
- про интеграцию code coverage с nosetest
- рассказать о том, какин нужно писать тесты, а какие не нужно (антипаттерны).
С этими вещами приходится сталкиваться в реальной разработке и мне кажется, что статья с описанием подобных вещей была бы полезнее.
В ближайшие три недели - ни про что, на днях уезжаю в жаркие страны...
А так, могу написать про питон, джангу, много чего, если в теме будет заинтересовано сообщество.
А так, могу написать про питон, джангу, много чего, если в теме будет заинтересовано сообщество.
В прошлом посте http://welinux.ru/post/4684/ я попытался привести пример более сложного способа тестирования. Но была просьба начать с вещей по проще. В TDD главное понять основу. Всю методику я не расскажу для этого есть соответствующие книги того же Кента Бэка, но вот своим опытом я пытаюсь поделиться:))
Новичкам надо сразу давать программирование, как инженерную дисциплину, а то в последнее время народ начал такой говнокод, что индусы плачут, его читая.
К слову, мы у себя в конторе прям сразу же с первого же занятия ввели TDD. И знаете, нормально восприняли, благо что в питоне с этим всё нормально - и доктесты, и юнит и всё что хочешь. И при этом не надо ничего перекомпиливать.
Так.. О чём это я? А!.. Ну, собственно, я тоже хотел всё это посоветовать, но видимо, у RANUX уже есть какая-то программа в плане, так что ждём новых постов и там уже обсудим.
А вообще конечно было бы неплохо сварганить "новый курс молодого бойца", осветив в нём всё, что не преподают в институтах, и с чем начинающий програмер сталкивается на предприятиях.
К слову, мы у себя в конторе прям сразу же с первого же занятия ввели TDD. И знаете, нормально восприняли, благо что в питоне с этим всё нормально - и доктесты, и юнит и всё что хочешь. И при этом не надо ничего перекомпиливать.
Так.. О чём это я? А!.. Ну, собственно, я тоже хотел всё это посоветовать, но видимо, у RANUX уже есть какая-то программа в плане, так что ждём новых постов и там уже обсудим.
А вообще конечно было бы неплохо сварганить "новый курс молодого бойца", осветив в нём всё, что не преподают в институтах, и с чем начинающий програмер сталкивается на предприятиях.
Да, TDD и прочими юнит-тестами такая беда: если их с самого начала не начать юзать, то потом чем больше кода, тем сложнее его ввести =(
Я тоже всегда хотел работать в конторе где TDD и Python, но пока-что приходиться рыться в системах с быдлокодом:( В общем, удовольствия от быдлокодерских систем не испытываю, скорее одно сплошное раздражение, а покрывать тестами и рефакторить в одиночку желания нет.
Идей полно, вот только времени не всегда хватает, но в любом случае продолжение будет:)
Так.. О чём это я? А!.. Ну, собственно, я тоже хотел всё это посоветовать, но видимо, у RANUX уже есть какая-то программа в плане, так что ждём новых постов и там уже обсудим.
Идей полно, вот только времени не всегда хватает, но в любом случае продолжение будет:)
А вообще конечно было бы неплохо сварганить "новый курс молодого бойца", осветив в нём всё, что не преподают в институтах, и с чем начинающий програмер сталкивается на предприятиях.
Я бы такой пост с удовольствием почитал, даже если бы это был просто список ссылок на актуальные подходы, алгоритмы, книги и прочее.
Мужики! Я прошу прощения за оффтопик, а может кто-нибудь написать про программирование под андроид, полагаю, это по теме ресурса.
Вот только не про то, как поставить эклипс и прикрутить к нему андроид SDK и плагины, а реально работающую программу разобрать.
Вот это было бы нереально круто!
Вот только не про то, как поставить эклипс и прикрутить к нему андроид SDK и плагины, а реально работающую программу разобрать.
Вот это было бы нереально круто!
Спасибо за статью! Всё выполнил.
Задание по факториалу сделал, но почему-то не удалось выполнить полную проверку на натуральность числа. Подробности на pastie.org
В следующей части, пожалуйста, не забудьте снова напомнить про все шаги TTD (а то вылетит из головы как что и зачем) и научить пользоваться аргументами, переданными из командной строки:
fact.py -n 5 //так вроде по POSIX правильно
Задание по факториалу сделал, но почему-то не удалось выполнить полную проверку на натуральность числа. Подробности на pastie.org
В следующей части, пожалуйста, не забудьте снова напомнить про все шаги TTD (а то вылетит из головы как что и зачем) и научить пользоваться аргументами, переданными из командной строки:
fact.py -n 5 //так вроде по POSIX правильно
Ты, наверное, хотел
По аргументам -- доки по argparse, getopt.
Вот тут еще человек скрипт выкладывал с опциями.
if n >= 0 and n % 1 == 0
По аргументам -- доки по argparse, getopt.
Вот тут еще человек скрипт выкладывал с опциями.
потмоу что тесты приходят и уходят, а код остаётся.