SlideShare una empresa de Scribd logo
1 de 36
Descargar para leer sin conexión
TDD
или как я стараюсь писать код

Владимир Филонов
labbler.com
Теория TDD
“Разработка через тестирование (англ. test-driven
  development, TDD) — техника разработки
  программного обеспечения, которая основывается
  на повторении очень коротких циклов разработки:
  сначала пишется тест, покрывающий желаемое
  изменение, затем пишется код, который позволит
  пройти тест, и под конец проводится рефакторинг
  нового кода к соответствующим стандартам.” ©
  Wikipedia.org
Тесты



Рефакто-
                   Код
  ринг
Зачем все это?
Говорят, что TDD помогает
•  Улучшить качество кода
•  Уменьшить количество ошибок и багов
•  Ускорить разработку
В чем сила, брат?
В чем разница?


           Тесты                    Код


Рефакто-                                  Рефакто-
  ринг             Код      Тесты           ринг
IMHO
Вектор мышления
Сначала код:
•  Разработчик концентрируется на отдельных частях
   кода больше чем на общем дизайне
•  К моменту написания тестов разработчик уже
   устает
•  Тесты пишутся уже с учетом особенностей
   реализации, в том числе и костылей, если таковые
   присутствуют
class OneFieldForm(forms.Form):
   value = forms.IntegerField()

class SimpleView(View):
   def get(self, *args, **kwargs):
     form = OneFieldForm()
        return render_template(form)
   def post(self, *args, **kwargs):
     form = OneFieldForm(self.request.POST)
     if form.is_valid():
        #Какой-то сложный, утомительный код, который
        #использует значение из формы
        return render_to_response(“success.html")
     else:
         return render_template(form)
   def render_template(self, form):
     context = { "form": form,}
     return render_to_response("template.html", context)
class SimpleViewTestCase(TestCase):

    def test_simple_view(self):
      response = self.client.get(”/”)
      self.assertEqual(response.tempates[0].name, “template.html ")

      response2 = self.client.post(”/”)
      self.assertEqual(response2.tempates[0].name, “template.html")

      response3 = self.client.post(”/”, {“count”: 1})
      self.assertEqual(response3.tempates[0].name, “success.html")

.
Ситуации

class OneFieldForm(forms.Form):
   value = forms.CharField()




if “value” in self.request.POST and 
                             self.request.POST[“value”]:
TDD
•  При написании тестов, мы не отвлекаемся на
   детали реализации
•  Более чёткое и целостное представление о
   дизайне кода
•  Выше скорость написания кода
•  Хорошего кода ;)
•  Меньше рефакторинга
Смена исполнителя
•  Проще понять, что уже сделано, а что еще нет –
   достаточно запустить тесты
•  Тесты как документация – проще разобраться в уже
   написанном коде
•  Более отчуждаемый код
Человечные интерфейсы
•  Сразу смотрим на задачу с позиции пользователя
   интерфейсов
•  Не делаем допущений, основанных на знании
   деталей реализации
•  Ниже порог вхождения, меньше подводных камней
•  Более отчуждаемый код
Мотивация
Обычное течение разработки
•  Начало. Уровень мотивации высокий, все рвутся в
   бой
•  Понеслась
  –  Имплементация
  –  Передача в QA
  –  Баги
  –  Дебагинг
  –  Мотивация = - 1* Баги
TDD
•  Тесты пишутся на первой волне энтузиазма
•  Для написания кода после тестов появляются
   дополнительные стимулы:
  –  Четко поставленная цель: пройти все тесты
  –  Каждый пройденный тест – достижение
  –  Это поддерживает положительный настрой
•  Стимулы для написания тестов после кода




  –  Требуется очень хорошая самоорганизация
  –  Формальных требований может быть недостаточно для
     написания хороших тестов
Acceptance TDD
•  Пишем приёмочные тесты и ставим задачи
   команде
•  Приёмочные тесты – тесты верхнего уровня
   абстракции
•  Сами пишем тесты на невалидные входные данные
•  Кто, кроме нас? :)

•  Сам я ещё не пробовал, но очень хочу
Как писать тесты до
       кода?
•  От абстракций верхнего уровня - к абстракциям нижних
   –  Глобальные вещи (views) -> API, DAO -> утилитарные методы
•  Проще показать на примере
Сделаем виртуальную библиотеку.
Книга - название, автор, ISBN
Читатель
Чтобы получить билет, надо зарегистрироваться. Для простоты, в
качестве номера будем использовать django.contrib.auth.models.User.id
Читатели могут брать/сдавать книги, но не более 2х одновременно.
Если книгу кто-то взял, то другому ее не получить.
Брать книги можно по:
•  1. Название+Автор
•  2. ISBN
#Книги: title, author, year, isbn
#
#Капитал, Кащей Б.С., 942 г., 1234-5678-9
#100 диетических блюд из репы, Прекрасная В., 1142 г.,
#                                         4321-8765-9
#Ковка подков, Гефест, 2675 г. до н.э. 9876-5432-1
#Бустâн, Абу Мухаммад Муслих ад-Дин ибн Абд Аллах Саади
#                          Ширази, 1257 г., 6789-2345-1

class LibraryViewsTestCase(TestCase):

    def setUp(self):
        self.ivan = User.objects.get(username="ivan")
        self.maria = User.objects.get(username="maria")
        self.books = INITIAL_BOOKS_LIST

    def test_library_urls(self):
        self.assertEqual(reverse("library:take"), "/take/")
        self.assertEqual(reverse("library:return"), "/return/")
def test_get_book_view__unauth(self):
    """
    Книжки можно раздавать только авторизованным пользователям
    """

   response = self.client.post("/take/", {"isbn": "1234-5678-9"})
   self.assertEqual(response.status_code, 301)

   self.client.login(username="ivan", password="durak")
   response = self.client.post("/take/", {"isbn": "1234-5678-9"})
   self.assertEqual(response.status_code, 200)
def test_get_book_view__isbn(self):
       """
       Наберем книжек по ISBN
       """
       self.client.login(username="ivan", password="pozhaluista")

       #Возьмем книгу
       response = self.client.post("/take/", {"isbn": "1234-5678-9"})
       self.assertEqual(response.status_code, 200)
       self.assertIn("book", response.context)
       self.assertEqual(response.context["book"]["title"], u"Капитал")
       self.assertEqual(response.templates[0].name, "take_success.html")
       self.assertEqual(get_user_books_count(self.ivan), 1)
       self.assertIn(self.books[0], get_user_books(self.ivan))

       #Еще одну
       self.client.post("/take/", {"isbn": "9876-5432-1"})
       self.assertEqual(get_user_books_count(self.ivan), 2)
       self.assertIn(self.books[0], get_user_books(self.ivan))
       self.assertIn(self.books[2], get_user_books(self.ivan))
#Поробуем третью
failed_response = self.client.post("/take/", {"isbn": "6789-2345-1"})
self.assertIn("book", response.context)
self.assertEqual(response.context["book"]["title"], u"Бустâн")
self.assertEqual(response.templates[0].name, "take_failed.html")
self.assertIn("error", response.context)
self.assertEqual(response.context["error"], u"Хватит уже")

self.assertEqual(get_user_books_count(self.ivan), 2)
self.assertIn(self.books[0], get_user_books(self.ivan))
self.assertIn(self.books[2], get_user_books(self.ivan))
def test_get_book_view__title_and_author(self):
    """
    Берем книги по заголовку и автору
    """

def test_get_book_view__taken(self):
    """
    Попробуем взять книгу, которую уже унес кто-то
    """

def test_get_book_view__again(self):
    """
    Попробуем взять одну и ту же книгу дважды
    """

def test_get_book_view__unknown(self):
     """
     Попробуем взять книгу, которой нет в библиотеке
     """
#...
#Возврат книги, возврат не взятой книги,
#возврат книги не из библиотеки
Полученные тесты можно
 использовать для ATDD
class LibriatyDaoTestCase(TestCase):
    """
    Следующий уровень - функции, которые нам понадобятся,
    чтобы решить ситуации, описанные выше
    """
    def test_get_book_by_isbn(self):
        """
        Получаем их базы книгу по isbn
        """

   def test_get_book_by_title_and_author(self):
       """
       Получаем из базы книгу по isbn
       """

   def test_user_has_book(self):
       """
       Есть ли эта книга у читателя
       """
def test_get_user_books(self):
    """
    Все книги которые есть у читателя
    """

def test_get_user_books_count(self):
    """
    Сколько книг у читателя
    """

def test_book_is_owned(self):
    """
    Взяли ли кто-то эту книгу
    """
Та-дааа!
Эпилог
•  Более продуманный дизайн кода к моменту начала
   реализации
•  Как следствие - более чистый код
•  Возможно, более быстрая реализация
•  Лучшее покрытие тестами (как по качеству, так и по
   количеству)
•  Дополнительный источник мотивации в процессе
•  Более отчуждаемый код
•  Меньше багов, а значит и меньше итераций «QA-
   багфиксинг»
Спасибо!
          И…
Немного саморекламы =)
https://labbler.com
mailto: vladimir@labbler.com
Спасибо!

Más contenido relacionado

La actualidad más candente

Доклад Сергея Аверина на DevConf 2013. "Распространенные ошибки применения ба...
Доклад Сергея Аверина на DevConf 2013. "Распространенные ошибки применения ба...Доклад Сергея Аверина на DevConf 2013. "Распространенные ошибки применения ба...
Доклад Сергея Аверина на DevConf 2013. "Распространенные ошибки применения ба...
Badoo Development
 
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Andrey Rebrov
 
Производительность и надежность Docsvision 5
Производительность и надежность Docsvision 5Производительность и надежность Docsvision 5
Производительность и надежность Docsvision 5
Docsvision
 

La actualidad más candente (20)

Class queries
Class queriesClass queries
Class queries
 
Метапрограммирование с примерами на JavaScript
Метапрограммирование с примерами на JavaScriptМетапрограммирование с примерами на JavaScript
Метапрограммирование с примерами на JavaScript
 
Доклад Сергея Аверина на DevConf 2013. "Распространенные ошибки применения ба...
Доклад Сергея Аверина на DevConf 2013. "Распространенные ошибки применения ба...Доклад Сергея Аверина на DevConf 2013. "Распространенные ошибки применения ба...
Доклад Сергея Аверина на DevConf 2013. "Распространенные ошибки применения ба...
 
NoSql. Фокус на тестирование
NoSql. Фокус на тестированиеNoSql. Фокус на тестирование
NoSql. Фокус на тестирование
 
Clojure: Lisp for the modern world (русская версия)
Clojure: Lisp for the modern world (русская версия)Clojure: Lisp for the modern world (русская версия)
Clojure: Lisp for the modern world (русская версия)
 
JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.
 
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
 
Особенности тестирования NoSql приложений
Особенности тестирования NoSql приложенийОсобенности тестирования NoSql приложений
Особенности тестирования NoSql приложений
 
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)
 
Изоморфный JavaScript — будущее уже здесь
Изоморфный JavaScript — будущее уже здесьИзоморфный JavaScript — будущее уже здесь
Изоморфный JavaScript — будущее уже здесь
 
MongoDB. Фокус на тестирование
MongoDB. Фокус на тестированиеMongoDB. Фокус на тестирование
MongoDB. Фокус на тестирование
 
Быстро о быстром
Быстро о быстромБыстро о быстром
Быстро о быстром
 
Basis.js – «под капотом»
Basis.js – «под капотом»Basis.js – «под капотом»
Basis.js – «под капотом»
 
DOM-шаблонизаторы – не только "быстро"
DOM-шаблонизаторы – не только "быстро"DOM-шаблонизаторы – не только "быстро"
DOM-шаблонизаторы – не только "быстро"
 
2014 Jeeconf - Geb Spock
2014 Jeeconf - Geb Spock2014 Jeeconf - Geb Spock
2014 Jeeconf - Geb Spock
 
Инструменты разные нужны, инструменты разные важны
Инструменты разные нужны, инструменты разные важныИнструменты разные нужны, инструменты разные важны
Инструменты разные нужны, инструменты разные важны
 
Automation Functional Testing in Agile Projects
Automation Functional Testing in Agile ProjectsAutomation Functional Testing in Agile Projects
Automation Functional Testing in Agile Projects
 
SPA инструменты
SPA инструментыSPA инструменты
SPA инструменты
 
JavaScript Базовый. Занятие 11.
JavaScript Базовый. Занятие 11.JavaScript Базовый. Занятие 11.
JavaScript Базовый. Занятие 11.
 
Производительность и надежность Docsvision 5
Производительность и надежность Docsvision 5Производительность и надежность Docsvision 5
Производительность и надежность Docsvision 5
 

Similar a TDD или как я стараюсь писать код

Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"
Python Meetup
 
Повышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииПовышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документации
CEE-SEC(R)
 
«DevOps — это о передаче смысла» — Александр Титов, Express 42
«DevOps — это о передаче смысла» — Александр Титов, Express 42«DevOps — это о передаче смысла» — Александр Титов, Express 42
«DevOps — это о передаче смысла» — Александр Титов, Express 42
DevDay
 
Михаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с CodeceptionМихаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с Codeception
Albina Tiupa
 
М. Боднарчук Современное функциональное тестирование с Codeception
М. Боднарчук Современное функциональное тестирование с CodeceptionМ. Боднарчук Современное функциональное тестирование с Codeception
М. Боднарчук Современное функциональное тестирование с Codeception
Albina Tiupa
 
Язык программирования Scala / Владимир Успенский (TCS Bank)
Язык программирования Scala / Владимир Успенский (TCS Bank)Язык программирования Scala / Владимир Успенский (TCS Bank)
Язык программирования Scala / Владимир Успенский (TCS Bank)
Ontico
 
TestGuy - эмулируем вашего тестировщика
TestGuy - эмулируем вашего тестировщикаTestGuy - эмулируем вашего тестировщика
TestGuy - эмулируем вашего тестировщика
davertmik
 
Easy authcache 2 кеширование для pro родионов игорь
Easy authcache 2   кеширование для pro родионов игорьEasy authcache 2   кеширование для pro родионов игорь
Easy authcache 2 кеширование для pro родионов игорь
drupalconf
 

Similar a TDD или как я стараюсь писать код (20)

TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать код
 
Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"
 
BDD
BDDBDD
BDD
 
Повышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииПовышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документации
 
«DevOps — это о передаче смысла» — Александр Титов, Express 42
«DevOps — это о передаче смысла» — Александр Титов, Express 42«DevOps — это о передаче смысла» — Александр Титов, Express 42
«DevOps — это о передаче смысла» — Александр Титов, Express 42
 
Лекция 11. Тестирование.
Лекция 11. Тестирование.Лекция 11. Тестирование.
Лекция 11. Тестирование.
 
Михаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с CodeceptionМихаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с Codeception
 
М. Боднарчук Современное функциональное тестирование с Codeception
М. Боднарчук Современное функциональное тестирование с CodeceptionМ. Боднарчук Современное функциональное тестирование с Codeception
М. Боднарчук Современное функциональное тестирование с Codeception
 
HSE{Consult}: DevOps – новая методология разработки
HSE{Consult}: DevOps – новая методология разработкиHSE{Consult}: DevOps – новая методология разработки
HSE{Consult}: DevOps – новая методология разработки
 
DevOps или исскуство ухода за Интернет-проектом
DevOps или исскуство ухода за Интернет-проектомDevOps или исскуство ухода за Интернет-проектом
DevOps или исскуство ухода за Интернет-проектом
 
2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
 
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNgДело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
 
UI+unit testing in iOS
UI+unit testing in iOSUI+unit testing in iOS
UI+unit testing in iOS
 
Язык программирования Scala / Владимир Успенский (TCS Bank)
Язык программирования Scala / Владимир Успенский (TCS Bank)Язык программирования Scala / Владимир Успенский (TCS Bank)
Язык программирования Scala / Владимир Успенский (TCS Bank)
 
TestGuy - эмулируем вашего тестировщика
TestGuy - эмулируем вашего тестировщикаTestGuy - эмулируем вашего тестировщика
TestGuy - эмулируем вашего тестировщика
 
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
 
PowerShell
PowerShellPowerShell
PowerShell
 
Easy authcache 2 кеширование для pro родионов игорь
Easy authcache 2   кеширование для pro родионов игорьEasy authcache 2   кеширование для pro родионов игорь
Easy authcache 2 кеширование для pro родионов игорь
 
Codeception Introduction
Codeception IntroductionCodeception Introduction
Codeception Introduction
 
Tdd php
Tdd phpTdd php
Tdd php
 

Más de MoscowDjango

Cyclone + Eventsource (realtime push-сообщения)
Cyclone + Eventsource (realtime push-сообщения)Cyclone + Eventsource (realtime push-сообщения)
Cyclone + Eventsource (realtime push-сообщения)
MoscowDjango
 
Работа со статикой в Django
Работа со статикой в DjangoРабота со статикой в Django
Работа со статикой в Django
MoscowDjango
 
Разработка расширяемых приложений на Django
Разработка расширяемых приложений на DjangoРазработка расширяемых приложений на Django
Разработка расширяемых приложений на Django
MoscowDjango
 
Class Based Generic Views в Django
Class Based Generic Views в DjangoClass Based Generic Views в Django
Class Based Generic Views в Django
MoscowDjango
 
Простой и удобный деплоймент проекта
Простой и удобный деплоймент проектаПростой и удобный деплоймент проекта
Простой и удобный деплоймент проекта
MoscowDjango
 
Django South. Миграция баз данных.
Django South. Миграция баз данных.  Django South. Миграция баз данных.
Django South. Миграция баз данных.
MoscowDjango
 
Журнальная вёрстка в Django
Журнальная вёрстка в DjangoЖурнальная вёрстка в Django
Журнальная вёрстка в Django
MoscowDjango
 

Más de MoscowDjango (11)

Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и Django
 
Пример fuzzy testing для поиска URL в тексте
Пример fuzzy testing для поиска URL в текстеПример fuzzy testing для поиска URL в тексте
Пример fuzzy testing для поиска URL в тексте
 
Cyclone + Eventsource (realtime push-сообщения)
Cyclone + Eventsource (realtime push-сообщения)Cyclone + Eventsource (realtime push-сообщения)
Cyclone + Eventsource (realtime push-сообщения)
 
Производительность в Django
Производительность в DjangoПроизводительность в Django
Производительность в Django
 
Django на Android
Django на AndroidDjango на Android
Django на Android
 
Работа со статикой в Django
Работа со статикой в DjangoРабота со статикой в Django
Работа со статикой в Django
 
Разработка расширяемых приложений на Django
Разработка расширяемых приложений на DjangoРазработка расширяемых приложений на Django
Разработка расширяемых приложений на Django
 
Class Based Generic Views в Django
Class Based Generic Views в DjangoClass Based Generic Views в Django
Class Based Generic Views в Django
 
Простой и удобный деплоймент проекта
Простой и удобный деплоймент проектаПростой и удобный деплоймент проекта
Простой и удобный деплоймент проекта
 
Django South. Миграция баз данных.
Django South. Миграция баз данных.  Django South. Миграция баз данных.
Django South. Миграция баз данных.
 
Журнальная вёрстка в Django
Журнальная вёрстка в DjangoЖурнальная вёрстка в Django
Журнальная вёрстка в Django
 

TDD или как я стараюсь писать код

  • 1. TDD или как я стараюсь писать код Владимир Филонов labbler.com
  • 2. Теория TDD “Разработка через тестирование (англ. test-driven development, TDD) — техника разработки программного обеспечения, которая основывается на повторении очень коротких циклов разработки: сначала пишется тест, покрывающий желаемое изменение, затем пишется код, который позволит пройти тест, и под конец проводится рефакторинг нового кода к соответствующим стандартам.” © Wikipedia.org
  • 3. Тесты Рефакто- Код ринг
  • 4. Зачем все это? Говорят, что TDD помогает •  Улучшить качество кода •  Уменьшить количество ошибок и багов •  Ускорить разработку
  • 6. В чем разница? Тесты Код Рефакто- Рефакто- ринг Код Тесты ринг
  • 8. Вектор мышления Сначала код: •  Разработчик концентрируется на отдельных частях кода больше чем на общем дизайне •  К моменту написания тестов разработчик уже устает •  Тесты пишутся уже с учетом особенностей реализации, в том числе и костылей, если таковые присутствуют
  • 9. class OneFieldForm(forms.Form): value = forms.IntegerField() class SimpleView(View): def get(self, *args, **kwargs): form = OneFieldForm() return render_template(form) def post(self, *args, **kwargs): form = OneFieldForm(self.request.POST) if form.is_valid(): #Какой-то сложный, утомительный код, который #использует значение из формы return render_to_response(“success.html") else: return render_template(form) def render_template(self, form): context = { "form": form,} return render_to_response("template.html", context)
  • 10. class SimpleViewTestCase(TestCase): def test_simple_view(self): response = self.client.get(”/”) self.assertEqual(response.tempates[0].name, “template.html ") response2 = self.client.post(”/”) self.assertEqual(response2.tempates[0].name, “template.html") response3 = self.client.post(”/”, {“count”: 1}) self.assertEqual(response3.tempates[0].name, “success.html") .
  • 11. Ситуации class OneFieldForm(forms.Form): value = forms.CharField() if “value” in self.request.POST and self.request.POST[“value”]:
  • 12. TDD •  При написании тестов, мы не отвлекаемся на детали реализации •  Более чёткое и целостное представление о дизайне кода •  Выше скорость написания кода •  Хорошего кода ;) •  Меньше рефакторинга
  • 13. Смена исполнителя •  Проще понять, что уже сделано, а что еще нет – достаточно запустить тесты •  Тесты как документация – проще разобраться в уже написанном коде •  Более отчуждаемый код
  • 14. Человечные интерфейсы •  Сразу смотрим на задачу с позиции пользователя интерфейсов •  Не делаем допущений, основанных на знании деталей реализации •  Ниже порог вхождения, меньше подводных камней •  Более отчуждаемый код
  • 16. Обычное течение разработки •  Начало. Уровень мотивации высокий, все рвутся в бой •  Понеслась –  Имплементация –  Передача в QA –  Баги –  Дебагинг –  Мотивация = - 1* Баги
  • 17. TDD •  Тесты пишутся на первой волне энтузиазма •  Для написания кода после тестов появляются дополнительные стимулы: –  Четко поставленная цель: пройти все тесты –  Каждый пройденный тест – достижение –  Это поддерживает положительный настрой
  • 18. •  Стимулы для написания тестов после кода –  Требуется очень хорошая самоорганизация –  Формальных требований может быть недостаточно для написания хороших тестов
  • 20. •  Пишем приёмочные тесты и ставим задачи команде •  Приёмочные тесты – тесты верхнего уровня абстракции •  Сами пишем тесты на невалидные входные данные •  Кто, кроме нас? :) •  Сам я ещё не пробовал, но очень хочу
  • 22. •  От абстракций верхнего уровня - к абстракциям нижних –  Глобальные вещи (views) -> API, DAO -> утилитарные методы •  Проще показать на примере Сделаем виртуальную библиотеку. Книга - название, автор, ISBN Читатель Чтобы получить билет, надо зарегистрироваться. Для простоты, в качестве номера будем использовать django.contrib.auth.models.User.id Читатели могут брать/сдавать книги, но не более 2х одновременно. Если книгу кто-то взял, то другому ее не получить. Брать книги можно по: •  1. Название+Автор •  2. ISBN
  • 23. #Книги: title, author, year, isbn # #Капитал, Кащей Б.С., 942 г., 1234-5678-9 #100 диетических блюд из репы, Прекрасная В., 1142 г., # 4321-8765-9 #Ковка подков, Гефест, 2675 г. до н.э. 9876-5432-1 #Бустâн, Абу Мухаммад Муслих ад-Дин ибн Абд Аллах Саади # Ширази, 1257 г., 6789-2345-1 class LibraryViewsTestCase(TestCase): def setUp(self): self.ivan = User.objects.get(username="ivan") self.maria = User.objects.get(username="maria") self.books = INITIAL_BOOKS_LIST def test_library_urls(self): self.assertEqual(reverse("library:take"), "/take/") self.assertEqual(reverse("library:return"), "/return/")
  • 24. def test_get_book_view__unauth(self): """ Книжки можно раздавать только авторизованным пользователям """ response = self.client.post("/take/", {"isbn": "1234-5678-9"}) self.assertEqual(response.status_code, 301) self.client.login(username="ivan", password="durak") response = self.client.post("/take/", {"isbn": "1234-5678-9"}) self.assertEqual(response.status_code, 200)
  • 25. def test_get_book_view__isbn(self): """ Наберем книжек по ISBN """ self.client.login(username="ivan", password="pozhaluista") #Возьмем книгу response = self.client.post("/take/", {"isbn": "1234-5678-9"}) self.assertEqual(response.status_code, 200) self.assertIn("book", response.context) self.assertEqual(response.context["book"]["title"], u"Капитал") self.assertEqual(response.templates[0].name, "take_success.html") self.assertEqual(get_user_books_count(self.ivan), 1) self.assertIn(self.books[0], get_user_books(self.ivan)) #Еще одну self.client.post("/take/", {"isbn": "9876-5432-1"}) self.assertEqual(get_user_books_count(self.ivan), 2) self.assertIn(self.books[0], get_user_books(self.ivan)) self.assertIn(self.books[2], get_user_books(self.ivan))
  • 26. #Поробуем третью failed_response = self.client.post("/take/", {"isbn": "6789-2345-1"}) self.assertIn("book", response.context) self.assertEqual(response.context["book"]["title"], u"Бустâн") self.assertEqual(response.templates[0].name, "take_failed.html") self.assertIn("error", response.context) self.assertEqual(response.context["error"], u"Хватит уже") self.assertEqual(get_user_books_count(self.ivan), 2) self.assertIn(self.books[0], get_user_books(self.ivan)) self.assertIn(self.books[2], get_user_books(self.ivan))
  • 27. def test_get_book_view__title_and_author(self): """ Берем книги по заголовку и автору """ def test_get_book_view__taken(self): """ Попробуем взять книгу, которую уже унес кто-то """ def test_get_book_view__again(self): """ Попробуем взять одну и ту же книгу дважды """ def test_get_book_view__unknown(self): """ Попробуем взять книгу, которой нет в библиотеке """ #... #Возврат книги, возврат не взятой книги, #возврат книги не из библиотеки
  • 28. Полученные тесты можно использовать для ATDD
  • 29. class LibriatyDaoTestCase(TestCase): """ Следующий уровень - функции, которые нам понадобятся, чтобы решить ситуации, описанные выше """ def test_get_book_by_isbn(self): """ Получаем их базы книгу по isbn """ def test_get_book_by_title_and_author(self): """ Получаем из базы книгу по isbn """ def test_user_has_book(self): """ Есть ли эта книга у читателя """
  • 30. def test_get_user_books(self): """ Все книги которые есть у читателя """ def test_get_user_books_count(self): """ Сколько книг у читателя """ def test_book_is_owned(self): """ Взяли ли кто-то эту книгу """
  • 33. •  Более продуманный дизайн кода к моменту начала реализации •  Как следствие - более чистый код •  Возможно, более быстрая реализация •  Лучшее покрытие тестами (как по качеству, так и по количеству) •  Дополнительный источник мотивации в процессе •  Более отчуждаемый код •  Меньше багов, а значит и меньше итераций «QA- багфиксинг»
  • 34. Спасибо! И… Немного саморекламы =)