Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
50 оттенков красного
Или тестирование без боли
Сергей Александрович, @darth_sim
Немного о себе
Меня зовут Сергей
Я разрабатываю backend у Злых Марсиан
Я люблю писать тесты
Сегодня мы:
Поговорим о том, зачем мы пишем тесты;
Уменьшим объем тестов без потери качества;
Уменьшим время написания и ц...
Disclaimer
Спорить о тестах можно много и долго. Все сказанное
здесь - мое мнение, основанное на личном опыте
Спонсор многих слайдов
Почему нужно писать
тесты?
Почему нужно писать тесты?
Чтобы беречь свое время при разработке;
Факт от Капитана: автоматические тесты выполняются на
п...
Почему нужно писать тесты?
Чтобы беречь свое время при разработке;
Чтобы не бояться что-то сломать;
Факт от Капитана: Все ...
Почему нужно писать тесты?
Чтобы беречь свое время при разработке;
Чтобы не бояться что-то сломать;
Чтобы держать архитект...
Почему нужно писать тесты?
Тесты - это взгляд на код со стороны.
Код сложно тестировать?
⬇
Код сложен, запутан
⬇
Код нужда...
Почему иногда мы не пишем
тесты?
Потому что часто тесты выглядят вот так:
Пора навести порядок!
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
Используйте говорящие имена
тестов
Если фреймворк не позволяет в полной мере описать тест
с помощью имени, напишите коммен...
Один тест - одна проверка
По выводу тестового фреймворка должно быть понятно,
какие конкретно действия выполняются не так,...
Один тест - одна проверка
Bad:
it 'creates message and sends it to the user via email' do
# ...
end
Good:
it 'creates mess...
Один тест - одна проверка
Аналогично для фреймворков без возможности подробно
описать тест
# Creates message
def test_send...
Один тест - одна проверка
Некоторые фреймворки позволяют писать комментарии к
проверкам. В таком случае разделение не так ...
Используйте контексты
Если фреймворк позволяет задавать контекст
тестирования — пользуйтесь этой возможностью
Используйте контексты
Bad:
it 'creates message when user is signed in' do
sign_in(user)
# ...
end
Good:
context 'when user...
Используйте контексты
Если фреймворк не поддерживает контексты, можно опять
обратиться к комментариям
# = When user is sig...
Правильные ожидания
Правильно подобраное ожидание - половина написанного
теста.
Правильные ожидания
Примеры хороших ожиданий:
Возвращаемое значение;
Изменения состояния класса, видимого извне;
Внешнее в...
Правильные ожидания
Примеры плохих ожиданий:
Изменения внутренних переменных класса;
Изменение состояния хранилища, исполь...
Правильные ожидания
Bad:
it "puts provided value to redis" do
subject.set("the value")
expect(REDIS.get("the key")).to eq(...
Правильные ожидания
Старайтесь максимально абстрагироваться от реализации
метода и сосредототочиться на результате
Mocks & stubs
Палка о двух концах:
Помогают достичь нужного уровня изоляции;
При злоупотреблении могут сделать тест беспол...
Mocks & stubs
Хорошие кандидаты:
Передаваемые на вход объекты;
Сетевые службы;
Функции с трудно прогнозируемым или трудно
...
Mocks & stubs
Нужно очень осторожно подходить к стабу БД.
Если не уверены на 100%, не делайте этого
Работа с внешними связями
Ситуация №1:
Функция foo объекта A (A.foo) проводит вычисления со
сложной логикой, основываясь н...
Работа с внешними связями
Вариант решения №1:
Написать тест, учитывающий логику функции B.bar.
Нарушение DRY, повторное те...
Работа с внешними связями
Вариант решения №2:
Создать условия для получения заранее известного
результата B.bar, использов...
Работа с внешними связями
Вариант решения №3:
Сделать stub B.bar с известным результатом,
использовать этот результат для ...
Работа с внешними связями
Проблема варианта №3: Изменение интерфейса
функции B.bar сломает код, но оставит тест ложно
поло...
Работа с внешними связями
Ситуация №2:
Метод foo объекта A (A.foo) проводит вычисления со
сложной логикой и затем вызывает...
Работа с внешними связями
Вариант решения №1:
Проверить side effect метода B.bar, учитывая его логику.
Нарушение DRY, повт...
Работа с внешними связями
Вариант решения №2:
Проверить некоторую неизменную часть side effect'а
метода B.bar, не зависящу...
Работа с внешними связями
Вариант решения №3:
Сделать stub B.bar, проверить факт его вызова после
выполнения A.foo.
Тест н...
Гораздо лучше!
Поддерживаем порядок
Составьте договоренности
Если работаете в команде, составьте styleguide для тестов,
хотя бы на словах. Это существенно сни...
Test first!
“Не доверяй тесту, который ты не видел
упавшим„
(народная мудрость)
Почему test first?
Если строить код на основе тестов, то у вас практически
не возникнет проблем с тестируемостью;
Хорошо о...
Почему test first?
Главный аргумент
Не зная точной реализации, вы будете вынуждены
тестировать только интерфейс, что и тре...
Test first
Перед написанием тестов, постройте дерево с помощью
контекстов. Постарайтесь отобразить все возможные
варианты ...
Итоги
Не гонитесь за test coverage;
Не будьте параноиком, определите для себя, что нужно
тестировать;
Описывайте тесты так...
Спасибо
Вопросы?
Upcoming SlideShare
Loading in …5
×

50 оттенков красного

1,185 views

Published on

Рассказ о том, как не превратить тестирование в боль

Published in: Technology
  • Be the first to comment

50 оттенков красного

  1. 1. 50 оттенков красного Или тестирование без боли Сергей Александрович, @darth_sim
  2. 2. Немного о себе Меня зовут Сергей Я разрабатываю backend у Злых Марсиан Я люблю писать тесты
  3. 3. Сегодня мы: Поговорим о том, зачем мы пишем тесты; Уменьшим объем тестов без потери качества; Уменьшим время написания и цену тестов; Упростим поддержку.
  4. 4. Disclaimer Спорить о тестах можно много и долго. Все сказанное здесь - мое мнение, основанное на личном опыте
  5. 5. Спонсор многих слайдов
  6. 6. Почему нужно писать тесты?
  7. 7. Почему нужно писать тесты? Чтобы беречь свое время при разработке; Факт от Капитана: автоматические тесты выполняются на порядок быстрее ручных.
  8. 8. Почему нужно писать тесты? Чтобы беречь свое время при разработке; Чтобы не бояться что-то сломать; Факт от Капитана: Все делают ошибки. Кто не делает ошибок, тот нагло врет.
  9. 9. Почему нужно писать тесты? Чтобы беречь свое время при разработке; Чтобы не бояться что-то сломать; Чтобы держать архитектуру приложения в форме. (касается в основном unit-тестов)
  10. 10. Почему нужно писать тесты? Тесты - это взгляд на код со стороны. Код сложно тестировать? ⬇ Код сложен, запутан ⬇ Код нуждается в рефакторинге
  11. 11. Почему иногда мы не пишем тесты? Потому что часто тесты выглядят вот так:
  12. 12. Пора навести порядок!
  13. 13. Test coverage
  14. 14. Test coverage Однажды программист спроcил Великого Мастера: «Какого покрытия тестами я должен достичь?» goo.gl/NH84c6
  15. 15. Test coverage Не дает никакого представления о том, насколько хорошо протестирован код; Показывает, какие места точно не протестированы, но не наоборот; Не дает никакого представления о качестве кода; Не та метрика, за которой стоит гнаться.
  16. 16. Test coverage 100% не стоит вашего времени; 90% — это очень хорошее покрытие; 70% вполне достаточно.
  17. 17. Test coverage “Мне платят за код, который работает, а не за тесты, поэтому моя философия заключается в том, чтобы тестировать настолько мало, насколько это возможно для достижения нужного уровня уверенности„ (Кент Бек)
  18. 18. Выбрасываем лишнее
  19. 19. Выбрасываем лишнее Тесты некритичного кода Если ошибка в коде не повлечет за собой серьезных последствий, то тестирование этого участка кода совсем не обязательно.
  20. 20. Выбрасываем лишнее Тесты поведения сторонних библиотек Большинство библиотек уже протестированы разработчиком; Если вас не устраивает, как они протестированы, лучше сделать контрибьют, чем держать тесты у себя.
  21. 21. Выбрасываем лишнее Косвенно выполненные проверки Проверка на наличие классов и методов; Проверка количества аргументов функций; Проверка на отсутствие исключений. Иногда такие проверки необходимы, но такие случаи редки.
  22. 22. Выбрасываем лишнее Тесты приватных методов Приватные методы проверяются тестами открытых методов, в которых они вызываются
  23. 23. Выбрасываем лишнее Тесты тривиального кода “Если я не делаю ошибок какого-то рода, я не тестирую код на их наличие„ (Кент Бек)
  24. 24. Приводим оставшееся в порядок
  25. 25. Приводим оставшееся в порядок “Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живёте„ (Мартин Голдинг) Верно и для тестов.
  26. 26. Используйте говорящие имена тестов Тест — это спецификация с функцией самопроверки. По названию теста должно быть понятно, что конкретно он проверяет.
  27. 27. Используйте говорящие имена тестов Bad: it 'works' do # ... end Good: it 'sends email to the user' do # ... end
  28. 28. Используйте говорящие имена тестов Если фреймворк не позволяет в полной мере описать тест с помощью имени, напишите комментарий # Sends email to the user def test_send_message # ... end
  29. 29. Один тест - одна проверка По выводу тестового фреймворка должно быть понятно, какие конкретно действия выполняются не так, как ожидалось.
  30. 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. 31. Один тест - одна проверка Аналогично для фреймворков без возможности подробно описать тест # Creates message def test_send_message__message_creation # ... end # Sends message to user def test_send_message__message_sending # ... end
  32. 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. 33. Используйте контексты Если фреймворк позволяет задавать контекст тестирования — пользуйтесь этой возможностью
  34. 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. 35. Используйте контексты Если фреймворк не поддерживает контексты, можно опять обратиться к комментариям # = When user is signed in ============================== # Creates message def test_send_message__signed_in__message_creation # ... end # = end When user is signed in
  36. 36. Правильные ожидания Правильно подобраное ожидание - половина написанного теста.
  37. 37. Правильные ожидания Примеры хороших ожиданий: Возвращаемое значение; Изменения состояния класса, видимого извне; Внешнее воздействие a.k.a. side effect; Обращение к сторонним объектам.
  38. 38. Правильные ожидания Примеры плохих ожиданий: Изменения внутренних переменных класса; Изменение состояния хранилища, используемого для хранения состояния тестируемого объекта; Вызовы приватных методов.
  39. 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. 40. Правильные ожидания Старайтесь максимально абстрагироваться от реализации метода и сосредототочиться на результате
  41. 41. Mocks & stubs Палка о двух концах: Помогают достичь нужного уровня изоляции; При злоупотреблении могут сделать тест бесполезным.
  42. 42. Mocks & stubs Хорошие кандидаты: Передаваемые на вход объекты; Сетевые службы; Функции с трудно прогнозируемым или трудно выводимым результатом, используемые в тестируемом методе.
  43. 43. Mocks & stubs Нужно очень осторожно подходить к стабу БД. Если не уверены на 100%, не делайте этого
  44. 44. Работа с внешними связями Ситуация №1: Функция foo объекта A (A.foo) проводит вычисления со сложной логикой, основываясь на результатах функции bar объекта B (B.bar); B.bar в свою очередь тоже проводит вычисления со сложной логикой. Необходимо протестировать метод A.foo
  45. 45. Работа с внешними связями Вариант решения №1: Написать тест, учитывающий логику функции B.bar. Нарушение DRY, повторное тестирование B.bar, тестирование логики, не относящейся к тестируемому методу
  46. 46. Работа с внешними связями Вариант решения №2: Создать условия для получения заранее известного результата B.bar, использовать этот результат для тестирования A.foo. Тест становится зависимым от логики B.bar. Изменение логики стороннего метода сломает тест.
  47. 47. Работа с внешними связями Вариант решения №3: Сделать stub B.bar с известным результатом, использовать этот результат для тестирования A.foo. Тест не зависит от логики B.bar
  48. 48. Работа с внешними связями Проблема варианта №3: Изменение интерфейса функции B.bar сломает код, но оставит тест ложно положительным. Решение: Это тот самый случай, когда чистый прогон функции с проверкой на отсутствие исключений имеет место быть.
  49. 49. Работа с внешними связями Ситуация №2: Метод foo объекта A (A.foo) проводит вычисления со сложной логикой и затем вызывает метод bar объекта B (B.bar); B.bar в свою очередь тоже реализует сложную логику. Необходимо протестировать метод A.foo
  50. 50. Работа с внешними связями Вариант решения №1: Проверить side effect метода B.bar, учитывая его логику. Нарушение DRY, повторное тестирование B.bar, тестирование логики, не относящейся к тестируемому методу
  51. 51. Работа с внешними связями Вариант решения №2: Проверить некоторую неизменную часть side effect'а метода B.bar, не зависящую от его логики. Пример: mailer отправляет письмо с неизменным заголовком. Тест не зависит от логики B.bar. Изменение интерфейса B.bar будет обнаружено сразу.
  52. 52. Работа с внешними связями Вариант решения №3: Сделать stub B.bar, проверить факт его вызова после выполнения A.foo. Тест не зависит от логики B.bar Имеет ту же проблему и аналогичное решение, что и вариант решения №3 предыдущей ситуации.
  53. 53. Гораздо лучше!
  54. 54. Поддерживаем порядок
  55. 55. Составьте договоренности Если работаете в команде, составьте styleguide для тестов, хотя бы на словах. Это существенно снизит порог вхождения в чужие тесты.
  56. 56. Test first! “Не доверяй тесту, который ты не видел упавшим„ (народная мудрость)
  57. 57. Почему test first? Если строить код на основе тестов, то у вас практически не возникнет проблем с тестируемостью; Хорошо организованные тесты позволяют продумать и описать структуру кода до реализации.
  58. 58. Почему test first? Главный аргумент Не зная точной реализации, вы будете вынуждены тестировать только интерфейс, что и требуется
  59. 59. Test first Перед написанием тестов, постройте дерево с помощью контекстов. Постарайтесь отобразить все возможные варианты развития событий.
  60. 60. Итоги Не гонитесь за test coverage; Не будьте параноиком, определите для себя, что нужно тестировать; Описывайте тесты так, чтобы другой человек мог понять тестируемый функционал; Тестируйте интерфейс, а не реализацию; Делайте unit-тесты независимыми от функционала других классов/методов; Используйте тесты как спецификацию для вашего кода;
  61. 61. Спасибо Вопросы?

×