SlideShare a Scribd company logo
1 of 61
Download to read offline
50 оттенков красного
Или тестирование без боли
Сергей Александрович, @darth_sim
Немного о себе
Меня зовут Сергей
Я разрабатываю backend у Злых Марсиан
Я люблю писать тесты
Сегодня мы:
Поговорим о том, зачем мы пишем тесты;
Уменьшим объем тестов без потери качества;
Уменьшим время написания и цену тестов;
Упростим поддержку.
Disclaimer
Спорить о тестах можно много и долго. Все сказанное
здесь - мое мнение, основанное на личном опыте
Спонсор многих слайдов
Почему нужно писать
тесты?
Почему нужно писать тесты?
Чтобы беречь свое время при разработке;
Факт от Капитана: автоматические тесты выполняются на
порядок быстрее ручных.
Почему нужно писать тесты?
Чтобы беречь свое время при разработке;
Чтобы не бояться что-то сломать;
Факт от Капитана: Все делают ошибки. Кто не делает
ошибок, тот нагло врет.
Почему нужно писать тесты?
Чтобы беречь свое время при разработке;
Чтобы не бояться что-то сломать;
Чтобы держать архитектуру приложения в форме.
(касается в основном unit-тестов)
Почему нужно писать тесты?
Тесты - это взгляд на код со стороны.
Код сложно тестировать?
⬇
Код сложен, запутан
⬇
Код нуждается в рефакторинге
Почему иногда мы не пишем
тесты?
Потому что часто тесты выглядят вот так:
Пора навести порядок!
Test coverage
Test coverage
Однажды программист спроcил Великого
Мастера: «Какого покрытия тестами я должен
достичь?»
goo.gl/NH84c6
Test coverage
Не дает никакого представления о том, насколько
хорошо протестирован код;
Показывает, какие места точно не протестированы, но
не наоборот;
Не дает никакого представления о качестве кода;
Не та метрика, за которой стоит гнаться.
Test coverage
100% не стоит вашего времени;
90% — это очень хорошее покрытие;
70% вполне достаточно.
Test coverage
“Мне платят за код, который работает, а не за
тесты, поэтому моя философия заключается в
том, чтобы тестировать настолько мало,
насколько это возможно для достижения
нужного уровня уверенности„
(Кент Бек)
Выбрасываем лишнее
Выбрасываем лишнее
Тесты некритичного кода
Если ошибка в коде не повлечет за собой серьезных
последствий, то тестирование этого участка кода совсем
не обязательно.
Выбрасываем лишнее
Тесты поведения сторонних библиотек
Большинство библиотек уже протестированы
разработчиком;
Если вас не устраивает, как они протестированы, лучше
сделать контрибьют, чем держать тесты у себя.
Выбрасываем лишнее
Косвенно выполненные проверки
Проверка на наличие классов и методов;
Проверка количества аргументов функций;
Проверка на отсутствие исключений.
Иногда такие проверки необходимы, но такие случаи
редки.
Выбрасываем лишнее
Тесты приватных методов
Приватные методы проверяются тестами открытых
методов, в которых они вызываются
Выбрасываем лишнее
Тесты тривиального кода
“Если я не делаю ошибок какого-то рода, я не
тестирую код на их наличие„
(Кент Бек)
Приводим оставшееся в
порядок
Приводим оставшееся в порядок
“Пишите код так, как будто сопровождать
его будет склонный к насилию психопат,
который знает, где вы живёте„
(Мартин Голдинг)
Верно и для тестов.
Используйте говорящие имена
тестов
Тест — это спецификация с функцией самопроверки. По
названию теста должно быть понятно, что конкретно он
проверяет.
Используйте говорящие имена
тестов
Bad:
it 'works' do
# ...
end
Good:
it 'sends email to the user' do
# ...
end
Используйте говорящие имена
тестов
Если фреймворк не позволяет в полной мере описать тест
с помощью имени, напишите комментарий
# Sends email to the user
def test_send_message
# ...
end
Один тест - одна проверка
По выводу тестового фреймворка должно быть понятно,
какие конкретно действия выполняются не так, как
ожидалось.
Один тест - одна проверка
Bad:
it 'creates message and sends it to the user via email' do
# ...
end
Good:
it 'creates message' do
# ...
end
it 'sends message to the user via email' do
# ...
end
Один тест - одна проверка
Аналогично для фреймворков без возможности подробно
описать тест
# Creates message
def test_send_message__message_creation
# ...
end
# Sends message to user
def test_send_message__message_sending
# ...
end
Один тест - одна проверка
Некоторые фреймворки позволяют писать комментарии к
проверкам. В таком случае разделение не так важно.
Пример для testify (go):
// Creates message
func Test_sendMessage(t *testing.T) {
// ...
assert.Equal(t, expected, actual,
"Should create message")
// ...
assert.Equal(t, expected, actual,
"Should send message to user via email")
// ...
}
Используйте контексты
Если фреймворк позволяет задавать контекст
тестирования — пользуйтесь этой возможностью
Используйте контексты
Bad:
it 'creates message when user is signed in' do
sign_in(user)
# ...
end
Good:
context 'when user is signed in' do
before { sign_in(user) }
it 'creates message' do
# ...
end
end
Используйте контексты
Если фреймворк не поддерживает контексты, можно опять
обратиться к комментариям
# = When user is signed in ==============================
# Creates message
def test_send_message__signed_in__message_creation
# ...
end
# = end When user is signed in
Правильные ожидания
Правильно подобраное ожидание - половина написанного
теста.
Правильные ожидания
Примеры хороших ожиданий:
Возвращаемое значение;
Изменения состояния класса, видимого извне;
Внешнее воздействие a.k.a. side effect;
Обращение к сторонним объектам.
Правильные ожидания
Примеры плохих ожиданий:
Изменения внутренних переменных класса;
Изменение состояния хранилища, используемого для
хранения состояния тестируемого объекта;
Вызовы приватных методов.
Правильные ожидания
Bad:
it "puts provided value to redis" do
subject.set("the value")
expect(REDIS.get("the key")).to eq("the value")
end
Good:
it "saves provided value" do
subject.set("the value")
expect(subject.get).to eq("the value")
end
Правильные ожидания
Старайтесь максимально абстрагироваться от реализации
метода и сосредототочиться на результате
Mocks & stubs
Палка о двух концах:
Помогают достичь нужного уровня изоляции;
При злоупотреблении могут сделать тест бесполезным.
Mocks & stubs
Хорошие кандидаты:
Передаваемые на вход объекты;
Сетевые службы;
Функции с трудно прогнозируемым или трудно
выводимым результатом, используемые в тестируемом
методе.
Mocks & stubs
Нужно очень осторожно подходить к стабу БД.
Если не уверены на 100%, не делайте этого
Работа с внешними связями
Ситуация №1:
Функция foo объекта A (A.foo) проводит вычисления со
сложной логикой, основываясь на результатах функции
bar объекта B (B.bar);
B.bar в свою очередь тоже проводит вычисления со
сложной логикой.
Необходимо протестировать метод A.foo
Работа с внешними связями
Вариант решения №1:
Написать тест, учитывающий логику функции B.bar.
Нарушение DRY, повторное тестирование B.bar,
тестирование логики, не относящейся к тестируемому
методу
Работа с внешними связями
Вариант решения №2:
Создать условия для получения заранее известного
результата B.bar, использовать этот результат для
тестирования A.foo.
Тест становится зависимым от логики B.bar.
Изменение логики стороннего метода сломает тест.
Работа с внешними связями
Вариант решения №3:
Сделать stub B.bar с известным результатом,
использовать этот результат для тестирования A.foo.
Тест не зависит от логики B.bar
Работа с внешними связями
Проблема варианта №3: Изменение интерфейса
функции B.bar сломает код, но оставит тест ложно
положительным.
Решение: Это тот самый случай, когда чистый прогон
функции с проверкой на отсутствие исключений имеет
место быть.
Работа с внешними связями
Ситуация №2:
Метод foo объекта A (A.foo) проводит вычисления со
сложной логикой и затем вызывает метод bar объекта B
(B.bar);
B.bar в свою очередь тоже реализует сложную логику.
Необходимо протестировать метод A.foo
Работа с внешними связями
Вариант решения №1:
Проверить side effect метода B.bar, учитывая его логику.
Нарушение DRY, повторное тестирование B.bar,
тестирование логики, не относящейся к тестируемому
методу
Работа с внешними связями
Вариант решения №2:
Проверить некоторую неизменную часть side effect'а
метода B.bar, не зависящую от его логики. Пример: mailer
отправляет письмо с неизменным заголовком.
Тест не зависит от логики B.bar. Изменение
интерфейса B.bar будет обнаружено сразу.
Работа с внешними связями
Вариант решения №3:
Сделать stub B.bar, проверить факт его вызова после
выполнения A.foo.
Тест не зависит от логики B.bar
Имеет ту же проблему и аналогичное решение, что и
вариант решения №3 предыдущей ситуации.
Гораздо лучше!
Поддерживаем порядок
Составьте договоренности
Если работаете в команде, составьте styleguide для тестов,
хотя бы на словах. Это существенно снизит порог
вхождения в чужие тесты.
Test first!
“Не доверяй тесту, который ты не видел
упавшим„
(народная мудрость)
Почему test first?
Если строить код на основе тестов, то у вас практически
не возникнет проблем с тестируемостью;
Хорошо организованные тесты позволяют продумать и
описать структуру кода до реализации.
Почему test first?
Главный аргумент
Не зная точной реализации, вы будете вынуждены
тестировать только интерфейс, что и требуется
Test first
Перед написанием тестов, постройте дерево с помощью
контекстов. Постарайтесь отобразить все возможные
варианты развития событий.
Итоги
Не гонитесь за test coverage;
Не будьте параноиком, определите для себя, что нужно
тестировать;
Описывайте тесты так, чтобы другой человек мог понять
тестируемый функционал;
Тестируйте интерфейс, а не реализацию;
Делайте unit-тесты независимыми от функционала
других классов/методов;
Используйте тесты как спецификацию для вашего кода;
Спасибо
Вопросы?

More Related Content

What's hot

обработка исключений в Java
обработка исключений в Javaобработка исключений в Java
обработка исключений в Java
metaform
 
Тестирование весна 2014 смешанное занятие 2
Тестирование весна 2014 смешанное занятие 2Тестирование весна 2014 смешанное занятие 2
Тестирование весна 2014 смешанное занятие 2
Technopark
 
20100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture0820100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture08
Computer Science Club
 
Особенности тестирования открытого ПО
Особенности тестирования открытого ПООсобенности тестирования открытого ПО
Особенности тестирования открытого ПО
Alexey Lyanguzov
 
Programmers' Mistakes for Dummies
Programmers' Mistakes for DummiesProgrammers' Mistakes for Dummies
Programmers' Mistakes for Dummies
COTOHA
 
Делаем Unit тесты проще
Делаем Unit тесты прощеДелаем Unit тесты проще
Делаем Unit тесты проще
Sergii Zelenin
 
Инструментальный подход к разработке протоколов
Инструментальный подход к разработке протоколовИнструментальный подход к разработке протоколов
Инструментальный подход к разработке протоколов
furj
 
Статический анализ кода: современный взгляд
Статический анализ кода: современный взглядСтатический анализ кода: современный взгляд
Статический анализ кода: современный взгляд
Andrey Karpov
 

What's hot (20)

обработка исключений в Java
обработка исключений в Javaобработка исключений в Java
обработка исключений в Java
 
Тестирование весна 2014 смешанное занятие 2
Тестирование весна 2014 смешанное занятие 2Тестирование весна 2014 смешанное занятие 2
Тестирование весна 2014 смешанное занятие 2
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибок
 
20100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture0820100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture08
 
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
 
Автоматическая генерация тестов по комментариям к программному коду
Автоматическая генерация тестов по комментариям к программному кодуАвтоматическая генерация тестов по комментариям к программному коду
Автоматическая генерация тестов по комментариям к программному коду
 
разработка бизнес приложений (8)
разработка бизнес приложений (8)разработка бизнес приложений (8)
разработка бизнес приложений (8)
 
Наследование и полиморфизм
Наследование и полиморфизмНаследование и полиморфизм
Наследование и полиморфизм
 
Тест-дизайн в тестировании ПО. Задача "Треугольник"
Тест-дизайн в тестировании ПО. Задача "Треугольник"Тест-дизайн в тестировании ПО. Задача "Треугольник"
Тест-дизайн в тестировании ПО. Задача "Треугольник"
 
Статический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMergeСтатический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMerge
 
Классы и объекты С#
Классы и объекты С#Классы и объекты С#
Классы и объекты С#
 
Особенности тестирования открытого ПО
Особенности тестирования открытого ПООсобенности тестирования открытого ПО
Особенности тестирования открытого ПО
 
Programmers' Mistakes for Dummies
Programmers' Mistakes for DummiesProgrammers' Mistakes for Dummies
Programmers' Mistakes for Dummies
 
Специфика тестирования проектов с открытым исходным кодом
Специфика тестирования проектов с открытым исходным кодомСпецифика тестирования проектов с открытым исходным кодом
Специфика тестирования проектов с открытым исходным кодом
 
Делаем Unit тесты проще
Делаем Unit тесты прощеДелаем Unit тесты проще
Делаем Unit тесты проще
 
Инструментальный подход к разработке протоколов
Инструментальный подход к разработке протоколовИнструментальный подход к разработке протоколов
Инструментальный подход к разработке протоколов
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practices
 
Как создать качественный статический анализатор
Как создать качественный статический анализаторКак создать качественный статический анализатор
Как создать качественный статический анализатор
 
Статический анализ и ROI
Статический анализ и ROIСтатический анализ и ROI
Статический анализ и ROI
 
Статический анализ кода: современный взгляд
Статический анализ кода: современный взглядСтатический анализ кода: современный взгляд
Статический анализ кода: современный взгляд
 

Similar to 2015-03-07 03 Сергей Александрович. 50 оттенков красного

Ошибки начинающих Tdd практиков, плюсы применения
Ошибки начинающих Tdd практиков, плюсы примененияОшибки начинающих Tdd практиков, плюсы применения
Ошибки начинающих Tdd практиков, плюсы применения
zheldak
 
Автотесты и образ мышления
Автотесты и образ мышленияАвтотесты и образ мышления
Автотесты и образ мышления
Andrei Zubov
 
Повышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииПовышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документации
CEE-SEC(R)
 
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Javakranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
Krivoy Rog IT Community
 

Similar to 2015-03-07 03 Сергей Александрович. 50 оттенков красного (20)

JavaTalks.Unit Testing.Part 1
JavaTalks.Unit Testing.Part 1JavaTalks.Unit Testing.Part 1
JavaTalks.Unit Testing.Part 1
 
QA Fest 2014. Алексей Лупан. Не тест-кейсы красят тестировщика, а...
QA Fest 2014. Алексей Лупан. Не тест-кейсы красят тестировщика, а...QA Fest 2014. Алексей Лупан. Не тест-кейсы красят тестировщика, а...
QA Fest 2014. Алексей Лупан. Не тест-кейсы красят тестировщика, а...
 
Ошибки начинающих Tdd практиков, плюсы применения
Ошибки начинающих Tdd практиков, плюсы примененияОшибки начинающих Tdd практиков, плюсы применения
Ошибки начинающих Tdd практиков, плюсы применения
 
Автотесты и образ мышления
Автотесты и образ мышленияАвтотесты и образ мышления
Автотесты и образ мышления
 
Собеседование на позицию Java Developer
Собеседование на позицию Java DeveloperСобеседование на позицию Java Developer
Собеседование на позицию Java Developer
 
Виталий Шибаев - Креативный менеджмент глазами разработчика: как выжить в agi...
Виталий Шибаев - Креативный менеджмент глазами разработчика: как выжить в agi...Виталий Шибаев - Креативный менеджмент глазами разработчика: как выжить в agi...
Виталий Шибаев - Креативный менеджмент глазами разработчика: как выжить в agi...
 
Unit Testing
Unit TestingUnit Testing
Unit Testing
 
Документация тестировщика - Александр Трибушный
Документация тестировщика - Александр ТрибушныйДокументация тестировщика - Александр Трибушный
Документация тестировщика - Александр Трибушный
 
Getting Tested: методология интеграционного тестирования
Getting Tested: методология интеграционного тестированияGetting Tested: методология интеграционного тестирования
Getting Tested: методология интеграционного тестирования
 
Continious integration-Automated Testing-Solid-Agile
Continious integration-Automated Testing-Solid-AgileContinious integration-Automated Testing-Solid-Agile
Continious integration-Automated Testing-Solid-Agile
 
презентация планов
презентация плановпрезентация планов
презентация планов
 
презентация планов
презентация плановпрезентация планов
презентация планов
 
UI+unit testing in iOS
UI+unit testing in iOSUI+unit testing in iOS
UI+unit testing in iOS
 
Повышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииПовышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документации
 
60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста
 
TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать код
 
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Javakranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
 
XP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeXP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy code
 
TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать код
 
QA Fest 2019. Андрей Солнцев. Десять причин моей ненависти
QA Fest 2019. Андрей Солнцев. Десять причин моей ненавистиQA Fest 2019. Андрей Солнцев. Десять причин моей ненависти
QA Fest 2019. Андрей Солнцев. Десять причин моей ненависти
 

More from Омские ИТ-субботники

2016-12-03 01 Вадим Литвинов. От 2D к 3D обзор методов реконструкции поверхно...
2016-12-03 01 Вадим Литвинов. От 2D к 3D обзор методов реконструкции поверхно...2016-12-03 01 Вадим Литвинов. От 2D к 3D обзор методов реконструкции поверхно...
2016-12-03 01 Вадим Литвинов. От 2D к 3D обзор методов реконструкции поверхно...
Омские ИТ-субботники
 
2016-12-03 02 Алексей Городецкий. Как пишут компиляторы
2016-12-03 02 Алексей Городецкий. Как пишут компиляторы2016-12-03 02 Алексей Городецкий. Как пишут компиляторы
2016-12-03 02 Алексей Городецкий. Как пишут компиляторы
Омские ИТ-субботники
 

More from Омские ИТ-субботники (20)

2017-08-12 01 Алексей Коровянский. Привет, ARKit!
2017-08-12 01 Алексей Коровянский. Привет, ARKit!2017-08-12 01 Алексей Коровянский. Привет, ARKit!
2017-08-12 01 Алексей Коровянский. Привет, ARKit!
 
2017-08-12 02 Антон Ковалев. Texture a.k.a AsyncDisplayKit
2017-08-12 02 Антон Ковалев. Texture a.k.a AsyncDisplayKit2017-08-12 02 Антон Ковалев. Texture a.k.a AsyncDisplayKit
2017-08-12 02 Антон Ковалев. Texture a.k.a AsyncDisplayKit
 
2017-05-06 02 Илья Сиганов. Зачем учить машины?
2017-05-06 02 Илья Сиганов. Зачем учить машины?2017-05-06 02 Илья Сиганов. Зачем учить машины?
2017-05-06 02 Илья Сиганов. Зачем учить машины?
 
2017 04-08 03 Максим Верзаков. Docker — жизнь, вселенная и все остальное
2017 04-08 03 Максим Верзаков. Docker — жизнь, вселенная и все остальное2017 04-08 03 Максим Верзаков. Docker — жизнь, вселенная и все остальное
2017 04-08 03 Максим Верзаков. Docker — жизнь, вселенная и все остальное
 
2017-04-08 01 Евгений Оськин. Video streaming: от идеи до нагруженной системы
2017-04-08 01 Евгений Оськин. Video streaming: от идеи до нагруженной системы2017-04-08 01 Евгений Оськин. Video streaming: от идеи до нагруженной системы
2017-04-08 01 Евгений Оськин. Video streaming: от идеи до нагруженной системы
 
2017-03-11 02 Денис Нелюбин. Docker & Ansible - лучшие друзья DevOps
2017-03-11 02 Денис Нелюбин. Docker & Ansible - лучшие друзья DevOps2017-03-11 02 Денис Нелюбин. Docker & Ansible - лучшие друзья DevOps
2017-03-11 02 Денис Нелюбин. Docker & Ansible - лучшие друзья DevOps
 
2017-03-11 01 Игорь Родионов. Docker swarm vs Kubernetes
2017-03-11 01 Игорь Родионов. Docker swarm vs Kubernetes2017-03-11 01 Игорь Родионов. Docker swarm vs Kubernetes
2017-03-11 01 Игорь Родионов. Docker swarm vs Kubernetes
 
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации
 
2017-02-04 02 Яков Лило. Решение задач
2017-02-04 02 Яков Лило. Решение задач2017-02-04 02 Яков Лило. Решение задач
2017-02-04 02 Яков Лило. Решение задач
 
2017-02-04 01 Евгений Тюменцев. Выразительные возможности языков программиро...
2017-02-04 01 Евгений Тюменцев. Выразительные возможности языков программиро...2017-02-04 01 Евгений Тюменцев. Выразительные возможности языков программиро...
2017-02-04 01 Евгений Тюменцев. Выразительные возможности языков программиро...
 
2016-12-03 01 Вадим Литвинов. От 2D к 3D обзор методов реконструкции поверхно...
2016-12-03 01 Вадим Литвинов. От 2D к 3D обзор методов реконструкции поверхно...2016-12-03 01 Вадим Литвинов. От 2D к 3D обзор методов реконструкции поверхно...
2016-12-03 01 Вадим Литвинов. От 2D к 3D обзор методов реконструкции поверхно...
 
2016-12-03 02 Алексей Городецкий. Как пишут компиляторы
2016-12-03 02 Алексей Городецкий. Как пишут компиляторы2016-12-03 02 Алексей Городецкий. Как пишут компиляторы
2016-12-03 02 Алексей Городецкий. Как пишут компиляторы
 
2016-12-03 03 Евгений Тюменцев. DSL на коленке
2016-12-03 03 Евгений Тюменцев. DSL на коленке2016-12-03 03 Евгений Тюменцев. DSL на коленке
2016-12-03 03 Евгений Тюменцев. DSL на коленке
 
2016-11-12 02 Николай Линкер. Чему Java может поучиться у Haskell и наоборот
2016-11-12 02 Николай Линкер. Чему Java может поучиться у Haskell и наоборот2016-11-12 02 Николай Линкер. Чему Java может поучиться у Haskell и наоборот
2016-11-12 02 Николай Линкер. Чему Java может поучиться у Haskell и наоборот
 
2016-11-12 03 Максим Дроздов. Навести порядок быстро, или как спасти оценки н...
2016-11-12 03 Максим Дроздов. Навести порядок быстро, или как спасти оценки н...2016-11-12 03 Максим Дроздов. Навести порядок быстро, или как спасти оценки н...
2016-11-12 03 Максим Дроздов. Навести порядок быстро, или как спасти оценки н...
 
2016-11-12 01 Егор Непомнящих. Агрегация и осведомленность
2016-11-12 01 Егор Непомнящих. Агрегация и осведомленность 2016-11-12 01 Егор Непомнящих. Агрегация и осведомленность
2016-11-12 01 Егор Непомнящих. Агрегация и осведомленность
 
2016-10-01 03 Андрей Аржанников. Что такое Bluetooth Low Energy?
2016-10-01 03 Андрей Аржанников. Что такое Bluetooth Low Energy?2016-10-01 03 Андрей Аржанников. Что такое Bluetooth Low Energy?
2016-10-01 03 Андрей Аржанников. Что такое Bluetooth Low Energy?
 
2016-10-01 02 Евгений Комаров. Как я сделал IoT-кикер
2016-10-01 02 Евгений Комаров. Как я сделал IoT-кикер2016-10-01 02 Евгений Комаров. Как я сделал IoT-кикер
2016-10-01 02 Евгений Комаров. Как я сделал IoT-кикер
 
2016-10-01 01 Звиад Кардава. Welcome to Internet of Things
2016-10-01 01 Звиад Кардава. Welcome to Internet of Things2016-10-01 01 Звиад Кардава. Welcome to Internet of Things
2016-10-01 01 Звиад Кардава. Welcome to Internet of Things
 
2016-09-17 03 Василий Полозов. WebRTC
2016-09-17 03 Василий Полозов. WebRTC2016-09-17 03 Василий Полозов. WebRTC
2016-09-17 03 Василий Полозов. WebRTC
 

2015-03-07 03 Сергей Александрович. 50 оттенков красного

  • 1. 50 оттенков красного Или тестирование без боли Сергей Александрович, @darth_sim
  • 2. Немного о себе Меня зовут Сергей Я разрабатываю backend у Злых Марсиан Я люблю писать тесты
  • 3. Сегодня мы: Поговорим о том, зачем мы пишем тесты; Уменьшим объем тестов без потери качества; Уменьшим время написания и цену тестов; Упростим поддержку.
  • 4. Disclaimer Спорить о тестах можно много и долго. Все сказанное здесь - мое мнение, основанное на личном опыте
  • 7. Почему нужно писать тесты? Чтобы беречь свое время при разработке; Факт от Капитана: автоматические тесты выполняются на порядок быстрее ручных.
  • 8. Почему нужно писать тесты? Чтобы беречь свое время при разработке; Чтобы не бояться что-то сломать; Факт от Капитана: Все делают ошибки. Кто не делает ошибок, тот нагло врет.
  • 9. Почему нужно писать тесты? Чтобы беречь свое время при разработке; Чтобы не бояться что-то сломать; Чтобы держать архитектуру приложения в форме. (касается в основном unit-тестов)
  • 10. Почему нужно писать тесты? Тесты - это взгляд на код со стороны. Код сложно тестировать? ⬇ Код сложен, запутан ⬇ Код нуждается в рефакторинге
  • 11. Почему иногда мы не пишем тесты? Потому что часто тесты выглядят вот так:
  • 14. Test coverage Однажды программист спроcил Великого Мастера: «Какого покрытия тестами я должен достичь?» goo.gl/NH84c6
  • 15. Test coverage Не дает никакого представления о том, насколько хорошо протестирован код; Показывает, какие места точно не протестированы, но не наоборот; Не дает никакого представления о качестве кода; Не та метрика, за которой стоит гнаться.
  • 16. Test coverage 100% не стоит вашего времени; 90% — это очень хорошее покрытие; 70% вполне достаточно.
  • 17. Test coverage “Мне платят за код, который работает, а не за тесты, поэтому моя философия заключается в том, чтобы тестировать настолько мало, насколько это возможно для достижения нужного уровня уверенности„ (Кент Бек)
  • 19. Выбрасываем лишнее Тесты некритичного кода Если ошибка в коде не повлечет за собой серьезных последствий, то тестирование этого участка кода совсем не обязательно.
  • 20. Выбрасываем лишнее Тесты поведения сторонних библиотек Большинство библиотек уже протестированы разработчиком; Если вас не устраивает, как они протестированы, лучше сделать контрибьют, чем держать тесты у себя.
  • 21. Выбрасываем лишнее Косвенно выполненные проверки Проверка на наличие классов и методов; Проверка количества аргументов функций; Проверка на отсутствие исключений. Иногда такие проверки необходимы, но такие случаи редки.
  • 22. Выбрасываем лишнее Тесты приватных методов Приватные методы проверяются тестами открытых методов, в которых они вызываются
  • 23. Выбрасываем лишнее Тесты тривиального кода “Если я не делаю ошибок какого-то рода, я не тестирую код на их наличие„ (Кент Бек)
  • 25. Приводим оставшееся в порядок “Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живёте„ (Мартин Голдинг) Верно и для тестов.
  • 26. Используйте говорящие имена тестов Тест — это спецификация с функцией самопроверки. По названию теста должно быть понятно, что конкретно он проверяет.
  • 27. Используйте говорящие имена тестов Bad: it 'works' do # ... end Good: it 'sends email to the user' do # ... end
  • 28. Используйте говорящие имена тестов Если фреймворк не позволяет в полной мере описать тест с помощью имени, напишите комментарий # Sends email to the user def test_send_message # ... end
  • 29. Один тест - одна проверка По выводу тестового фреймворка должно быть понятно, какие конкретно действия выполняются не так, как ожидалось.
  • 30. Один тест - одна проверка Bad: it 'creates message and sends it to the user via email' do # ... end Good: it 'creates message' do # ... end it 'sends message to the user via email' do # ... end
  • 31. Один тест - одна проверка Аналогично для фреймворков без возможности подробно описать тест # Creates message def test_send_message__message_creation # ... end # Sends message to user def test_send_message__message_sending # ... end
  • 32. Один тест - одна проверка Некоторые фреймворки позволяют писать комментарии к проверкам. В таком случае разделение не так важно. Пример для testify (go): // Creates message func Test_sendMessage(t *testing.T) { // ... assert.Equal(t, expected, actual, "Should create message") // ... assert.Equal(t, expected, actual, "Should send message to user via email") // ... }
  • 33. Используйте контексты Если фреймворк позволяет задавать контекст тестирования — пользуйтесь этой возможностью
  • 34. Используйте контексты Bad: it 'creates message when user is signed in' do sign_in(user) # ... end Good: context 'when user is signed in' do before { sign_in(user) } it 'creates message' do # ... end end
  • 35. Используйте контексты Если фреймворк не поддерживает контексты, можно опять обратиться к комментариям # = When user is signed in ============================== # Creates message def test_send_message__signed_in__message_creation # ... end # = end When user is signed in
  • 36. Правильные ожидания Правильно подобраное ожидание - половина написанного теста.
  • 37. Правильные ожидания Примеры хороших ожиданий: Возвращаемое значение; Изменения состояния класса, видимого извне; Внешнее воздействие a.k.a. side effect; Обращение к сторонним объектам.
  • 38. Правильные ожидания Примеры плохих ожиданий: Изменения внутренних переменных класса; Изменение состояния хранилища, используемого для хранения состояния тестируемого объекта; Вызовы приватных методов.
  • 39. Правильные ожидания Bad: it "puts provided value to redis" do subject.set("the value") expect(REDIS.get("the key")).to eq("the value") end Good: it "saves provided value" do subject.set("the value") expect(subject.get).to eq("the value") end
  • 40. Правильные ожидания Старайтесь максимально абстрагироваться от реализации метода и сосредототочиться на результате
  • 41. Mocks & stubs Палка о двух концах: Помогают достичь нужного уровня изоляции; При злоупотреблении могут сделать тест бесполезным.
  • 42. Mocks & stubs Хорошие кандидаты: Передаваемые на вход объекты; Сетевые службы; Функции с трудно прогнозируемым или трудно выводимым результатом, используемые в тестируемом методе.
  • 43. Mocks & stubs Нужно очень осторожно подходить к стабу БД. Если не уверены на 100%, не делайте этого
  • 44. Работа с внешними связями Ситуация №1: Функция foo объекта A (A.foo) проводит вычисления со сложной логикой, основываясь на результатах функции bar объекта B (B.bar); B.bar в свою очередь тоже проводит вычисления со сложной логикой. Необходимо протестировать метод A.foo
  • 45. Работа с внешними связями Вариант решения №1: Написать тест, учитывающий логику функции B.bar. Нарушение DRY, повторное тестирование B.bar, тестирование логики, не относящейся к тестируемому методу
  • 46. Работа с внешними связями Вариант решения №2: Создать условия для получения заранее известного результата B.bar, использовать этот результат для тестирования A.foo. Тест становится зависимым от логики B.bar. Изменение логики стороннего метода сломает тест.
  • 47. Работа с внешними связями Вариант решения №3: Сделать stub B.bar с известным результатом, использовать этот результат для тестирования A.foo. Тест не зависит от логики B.bar
  • 48. Работа с внешними связями Проблема варианта №3: Изменение интерфейса функции B.bar сломает код, но оставит тест ложно положительным. Решение: Это тот самый случай, когда чистый прогон функции с проверкой на отсутствие исключений имеет место быть.
  • 49. Работа с внешними связями Ситуация №2: Метод foo объекта A (A.foo) проводит вычисления со сложной логикой и затем вызывает метод bar объекта B (B.bar); B.bar в свою очередь тоже реализует сложную логику. Необходимо протестировать метод A.foo
  • 50. Работа с внешними связями Вариант решения №1: Проверить side effect метода B.bar, учитывая его логику. Нарушение DRY, повторное тестирование B.bar, тестирование логики, не относящейся к тестируемому методу
  • 51. Работа с внешними связями Вариант решения №2: Проверить некоторую неизменную часть side effect'а метода B.bar, не зависящую от его логики. Пример: mailer отправляет письмо с неизменным заголовком. Тест не зависит от логики B.bar. Изменение интерфейса B.bar будет обнаружено сразу.
  • 52. Работа с внешними связями Вариант решения №3: Сделать stub B.bar, проверить факт его вызова после выполнения A.foo. Тест не зависит от логики B.bar Имеет ту же проблему и аналогичное решение, что и вариант решения №3 предыдущей ситуации.
  • 55. Составьте договоренности Если работаете в команде, составьте styleguide для тестов, хотя бы на словах. Это существенно снизит порог вхождения в чужие тесты.
  • 56. Test first! “Не доверяй тесту, который ты не видел упавшим„ (народная мудрость)
  • 57. Почему test first? Если строить код на основе тестов, то у вас практически не возникнет проблем с тестируемостью; Хорошо организованные тесты позволяют продумать и описать структуру кода до реализации.
  • 58. Почему test first? Главный аргумент Не зная точной реализации, вы будете вынуждены тестировать только интерфейс, что и требуется
  • 59. Test first Перед написанием тестов, постройте дерево с помощью контекстов. Постарайтесь отобразить все возможные варианты развития событий.
  • 60. Итоги Не гонитесь за test coverage; Не будьте параноиком, определите для себя, что нужно тестировать; Описывайте тесты так, чтобы другой человек мог понять тестируемый функционал; Тестируйте интерфейс, а не реализацию; Делайте unit-тесты независимыми от функционала других классов/методов; Используйте тесты как спецификацию для вашего кода;