SlideShare une entreprise Scribd logo
1  sur  36
Télécharger pour lire hors ligne
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
Спасибо!

Contenu connexe

Tendances

Test Driven Development in .NET Applications
Test Driven Development in .NET ApplicationsTest Driven Development in .NET Applications
Test Driven Development in .NET ApplicationsAnton Vidishchev
 
Qa Automation - отбрасываем лишнее и тестируем суть
Qa Automation - отбрасываем лишнее и тестируем сутьQa Automation - отбрасываем лишнее и тестируем суть
Qa Automation - отбрасываем лишнее и тестируем сутьIgor Khrol
 
Grail: шаги для ваших Python-тестов
Grail: шаги для ваших Python-тестовGrail: шаги для ваших Python-тестов
Grail: шаги для ваших Python-тестовCodeFest
 
Как играть без игрока
Как играть без игрокаКак играть без игрока
Как играть без игрокаSQALab
 
Визуализация покрытия автоматизированными UI тестами
Визуализация покрытия автоматизированными UI тестамиВизуализация покрытия автоматизированными UI тестами
Визуализация покрытия автоматизированными UI тестамиSQALab
 
GUI-автоматизация в Telerik Test Studio
GUI-автоматизация в Telerik Test StudioGUI-автоматизация в Telerik Test Studio
GUI-автоматизация в Telerik Test StudioSQALab
 
Автоматизация тестирования: доступна каждому или удел избранных?
Автоматизация тестирования: доступна каждому или удел избранных?Автоматизация тестирования: доступна каждому или удел избранных?
Автоматизация тестирования: доступна каждому или удел избранных?SQALab
 
The fast and the continuous
The fast and the continuousThe fast and the continuous
The fast and the continuousSQALab
 
Непрерывная интеграция и автотесты. Сравнительный анализ инструментов
Непрерывная интеграция и автотесты. Сравнительный анализ инструментовНепрерывная интеграция и автотесты. Сравнительный анализ инструментов
Непрерывная интеграция и автотесты. Сравнительный анализ инструментовSQALab
 
Типичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverТипичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverIgor Khrol
 
UICov - инструмент анализа покрытия UI-тестами
UICov - инструмент анализа покрытия UI-тестамиUICov - инструмент анализа покрытия UI-тестами
UICov - инструмент анализа покрытия UI-тестамиSQALab
 
Принципы Solid на практике
Принципы Solid на практикеПринципы Solid на практике
Принципы Solid на практикеEatDog
 
История HERE Maps for Windows: меняемся не изменяя качеству
История HERE Maps for Windows: меняемся не изменяя качествуИстория HERE Maps for Windows: меняемся не изменяя качеству
История HERE Maps for Windows: меняемся не изменяя качествуSQALab
 
Шаблоны проектирования нагрузочных скриптов
Шаблоны проектирования нагрузочных скриптовШаблоны проектирования нагрузочных скриптов
Шаблоны проектирования нагрузочных скриптовSQALab
 
Webium: Page Objects in Python
Webium: Page Objects in PythonWebium: Page Objects in Python
Webium: Page Objects in PythonIgor Khrol
 
CodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестирования
CodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестированияCodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестирования
CodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестированияCodeFest
 
Организация процесса ручного тестирования
Организация процесса ручного тестированияОрганизация процесса ручного тестирования
Организация процесса ручного тестированияIT61
 
Повышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииПовышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииCEE-SEC(R)
 
Дефицит ресурсов тестирования... или нет?
Дефицит ресурсов тестирования... или нет?Дефицит ресурсов тестирования... или нет?
Дефицит ресурсов тестирования... или нет?SQALab
 
Артём Ерошенко, Станислав Селиверстов "Поиск багов в поиске"
Артём Ерошенко, Станислав Селиверстов "Поиск багов в поиске"Артём Ерошенко, Станислав Селиверстов "Поиск багов в поиске"
Артём Ерошенко, Станислав Селиверстов "Поиск багов в поиске"Yandex
 

Tendances (20)

Test Driven Development in .NET Applications
Test Driven Development in .NET ApplicationsTest Driven Development in .NET Applications
Test Driven Development in .NET Applications
 
Qa Automation - отбрасываем лишнее и тестируем суть
Qa Automation - отбрасываем лишнее и тестируем сутьQa Automation - отбрасываем лишнее и тестируем суть
Qa Automation - отбрасываем лишнее и тестируем суть
 
Grail: шаги для ваших Python-тестов
Grail: шаги для ваших Python-тестовGrail: шаги для ваших Python-тестов
Grail: шаги для ваших Python-тестов
 
Как играть без игрока
Как играть без игрокаКак играть без игрока
Как играть без игрока
 
Визуализация покрытия автоматизированными UI тестами
Визуализация покрытия автоматизированными UI тестамиВизуализация покрытия автоматизированными UI тестами
Визуализация покрытия автоматизированными UI тестами
 
GUI-автоматизация в Telerik Test Studio
GUI-автоматизация в Telerik Test StudioGUI-автоматизация в Telerik Test Studio
GUI-автоматизация в Telerik Test Studio
 
Автоматизация тестирования: доступна каждому или удел избранных?
Автоматизация тестирования: доступна каждому или удел избранных?Автоматизация тестирования: доступна каждому или удел избранных?
Автоматизация тестирования: доступна каждому или удел избранных?
 
The fast and the continuous
The fast and the continuousThe fast and the continuous
The fast and the continuous
 
Непрерывная интеграция и автотесты. Сравнительный анализ инструментов
Непрерывная интеграция и автотесты. Сравнительный анализ инструментовНепрерывная интеграция и автотесты. Сравнительный анализ инструментов
Непрерывная интеграция и автотесты. Сравнительный анализ инструментов
 
Типичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverТипичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriver
 
UICov - инструмент анализа покрытия UI-тестами
UICov - инструмент анализа покрытия UI-тестамиUICov - инструмент анализа покрытия UI-тестами
UICov - инструмент анализа покрытия UI-тестами
 
Принципы Solid на практике
Принципы Solid на практикеПринципы Solid на практике
Принципы Solid на практике
 
История HERE Maps for Windows: меняемся не изменяя качеству
История HERE Maps for Windows: меняемся не изменяя качествуИстория HERE Maps for Windows: меняемся не изменяя качеству
История HERE Maps for Windows: меняемся не изменяя качеству
 
Шаблоны проектирования нагрузочных скриптов
Шаблоны проектирования нагрузочных скриптовШаблоны проектирования нагрузочных скриптов
Шаблоны проектирования нагрузочных скриптов
 
Webium: Page Objects in Python
Webium: Page Objects in PythonWebium: Page Objects in Python
Webium: Page Objects in Python
 
CodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестирования
CodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестированияCodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестирования
CodeFest 2014. Павлов И. — Как делать прототипы в автоматизации тестирования
 
Организация процесса ручного тестирования
Организация процесса ручного тестированияОрганизация процесса ручного тестирования
Организация процесса ручного тестирования
 
Повышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииПовышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документации
 
Дефицит ресурсов тестирования... или нет?
Дефицит ресурсов тестирования... или нет?Дефицит ресурсов тестирования... или нет?
Дефицит ресурсов тестирования... или нет?
 
Артём Ерошенко, Станислав Селиверстов "Поиск багов в поиске"
Артём Ерошенко, Станислав Селиверстов "Поиск багов в поиске"Артём Ерошенко, Станислав Селиверстов "Поиск багов в поиске"
Артём Ерошенко, Станислав Селиверстов "Поиск багов в поиске"
 

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

TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать кодMoscowDjango
 
Роман Кокин «Организация тестирования в больших командах»
Роман Кокин «Организация тестирования в больших командах»Роман Кокин «Организация тестирования в больших командах»
Роман Кокин «Организация тестирования в больших командах»DataArt
 
Лекция 11. Тестирование.
Лекция 11. Тестирование.Лекция 11. Тестирование.
Лекция 11. Тестирование.Roman Brovko
 
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...Ontico
 
Jubula – TDD UI QA Automation Tool
Jubula – TDD UI QA Automation ToolJubula – TDD UI QA Automation Tool
Jubula – TDD UI QA Automation ToolCOMAQA.BY
 
М. Боднарчук Современное функциональное тестирование с Codeception
М. Боднарчук Современное функциональное тестирование с CodeceptionМ. Боднарчук Современное функциональное тестирование с Codeception
М. Боднарчук Современное функциональное тестирование с CodeceptionAlbina Tiupa
 
Solit 2014, Централизованное управление тестами с помощью TestLink, Зубович В...
Solit 2014, Централизованное управление тестами с помощью TestLink, Зубович В...Solit 2014, Централизованное управление тестами с помощью TestLink, Зубович В...
Solit 2014, Централизованное управление тестами с помощью TestLink, Зубович В...solit
 
Михаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с CodeceptionМихаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с CodeceptionAlbina Tiupa
 
TestLink
TestLinkTestLink
TestLinkISsoft
 
Вадим Зубович - Test Link
Вадим Зубович - Test LinkВадим Зубович - Test Link
Вадим Зубович - Test LinkQA Club Minsk
 
Test driven development in net
Test driven development in netTest driven development in net
Test driven development in netAlex Tumanoff
 
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...Andrey Rebrov
 
Simonova CSEDays
Simonova CSEDaysSimonova CSEDays
Simonova CSEDaysLiloSEA
 
Katerina Simonova CSEDays
Katerina Simonova CSEDaysKaterina Simonova CSEDays
Katerina Simonova CSEDaysLiloSEA
 
Katerina Simonova CSEDays
Katerina Simonova CSEDaysKaterina Simonova CSEDays
Katerina Simonova CSEDaysLiloSEA
 
Как построить свой фреймворк для автотестов?
Как построить свой фреймворк для автотестов?Как построить свой фреймворк для автотестов?
Как построить свой фреймворк для автотестов?Dmitry Buzdin
 
Метод No-Test-Cases: избавьтесь от тест-кейсов в тестировании
Метод No-Test-Cases: избавьтесь от тест-кейсов в тестированииМетод No-Test-Cases: избавьтесь от тест-кейсов в тестировании
Метод No-Test-Cases: избавьтесь от тест-кейсов в тестированииSQALab
 

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

TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать код
 
Роман Кокин «Организация тестирования в больших командах»
Роман Кокин «Организация тестирования в больших командах»Роман Кокин «Организация тестирования в больших командах»
Роман Кокин «Организация тестирования в больших командах»
 
Лекция 11. Тестирование.
Лекция 11. Тестирование.Лекция 11. Тестирование.
Лекция 11. Тестирование.
 
BDD
BDDBDD
BDD
 
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
 
Jubula – TDD UI QA Automation Tool
Jubula – TDD UI QA Automation ToolJubula – TDD UI QA Automation Tool
Jubula – TDD UI QA Automation Tool
 
М. Боднарчук Современное функциональное тестирование с Codeception
М. Боднарчук Современное функциональное тестирование с CodeceptionМ. Боднарчук Современное функциональное тестирование с Codeception
М. Боднарчук Современное функциональное тестирование с Codeception
 
Solit 2014, Централизованное управление тестами с помощью TestLink, Зубович В...
Solit 2014, Централизованное управление тестами с помощью TestLink, Зубович В...Solit 2014, Централизованное управление тестами с помощью TestLink, Зубович В...
Solit 2014, Централизованное управление тестами с помощью TestLink, Зубович В...
 
Михаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с CodeceptionМихаил Боднарчук Современное функциональное тестирование с Codeception
Михаил Боднарчук Современное функциональное тестирование с Codeception
 
UI+unit testing in iOS
UI+unit testing in iOSUI+unit testing in iOS
UI+unit testing in iOS
 
TestLink
TestLinkTestLink
TestLink
 
Вадим Зубович - Test Link
Вадим Зубович - Test LinkВадим Зубович - Test Link
Вадим Зубович - Test Link
 
Test driven development in net
Test driven development in netTest driven development in net
Test driven development in net
 
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
Автоматизируйте это немедленно или коллекция инструментов автотестирования с ...
 
Simonova CSEDays
Simonova CSEDaysSimonova CSEDays
Simonova CSEDays
 
Katerina Simonova CSEDays
Katerina Simonova CSEDaysKaterina Simonova CSEDays
Katerina Simonova CSEDays
 
Katerina Simonova CSEDays
Katerina Simonova CSEDaysKaterina Simonova CSEDays
Katerina Simonova CSEDays
 
Tdd php
Tdd phpTdd php
Tdd php
 
Как построить свой фреймворк для автотестов?
Как построить свой фреймворк для автотестов?Как построить свой фреймворк для автотестов?
Как построить свой фреймворк для автотестов?
 
Метод No-Test-Cases: избавьтесь от тест-кейсов в тестировании
Метод No-Test-Cases: избавьтесь от тест-кейсов в тестированииМетод No-Test-Cases: избавьтесь от тест-кейсов в тестировании
Метод No-Test-Cases: избавьтесь от тест-кейсов в тестировании
 

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

  • 1. TDD или как я стараюсь писать код Владимир Филонов labbler.com
  • 2. Теория TDD “Разработка через тестирование (англ. test-driven development, TDD) — техника разработки программного обеспечения, которая основывается на повторении очень коротких циклов разработки: сначала пишется тест, покрывающий желаемое изменение, затем пишется код, который позволит пройти тест, и под конец проводится рефакторинг нового кода к соответствующим стандартам.” © Wikipedia.org
  • 4. Зачем все это? Говорят, что TDD помогает •  Улучшить качество кода •  Уменьшить количество ошибок и багов •  Ускорить разработку
  • 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): """ Попробуем взять книгу, которой нет в библиотеке """ #... #Возврат книги, возврат не взятой книги, #возврат книги не из библиотеки
  • 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- багфиксинг»