JavaTalks.Unit Testing.Part 1

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    Notes on slide 1

    Основная цель – доказать, что код делает то, что от него требуется. Юнит тесты проверяют очень маленькие, изолированные кусочки функциональности. С учетом этих требований юнит тестов, разработчику приходится изменять архитектуру и логику работы приложения, чтобы: Было удобно тестировать Было удобно работать с тестируемым кодом Приходится менять интерфейсы, сигнатуры методов, области видимости Менять разбивку на методы

    В случае ненадежного кода, разработчику зачастую приходится изменять и переделывать код. Нередко огромные участки кода приходится переписывать. Поэтому очень важно тестировать код на низком уровне, чтобы маленькие кусочки были надежны и не порождали «волн» изменений по всему коду.

    То, что ожидает разработчик может отличаться от того, что требуется пользователю (разработчик учится системе вместе с разработкой системы) Мы живем в реальном мире, где вещи имеют свойство идти «не так». И поэтому, если мы не предусмотрим и не проверим, что все предусмотренное выполняется, то в большинстве случаев (по закону бутерброда – в самый ответственный момент – на демо высокому начальству), баг вылезет наружу. Код, на который нельзя надеятся – бесполезный. Но еще хуже, когда вы думаете , что на код можно надеятся. Никто не пишет идеальный код ( доказано математически, что начиная с определенного предела, в коде будут дефекты). Юнит тесты показывают, как ваш код будет использоваться клиентскими классами  юнит тесты ведут себя, как исполнительная документация.

    Это может быть только грубая идея – она уточнится в процессе. В идеале тест пишется «чуть впереди» основного класса. Этот процесс очень полезен т.к. вы пишите тест, как клиент тестируемого класса и вы четко видите, как класс будет использоваться.  в будущем не придется менять интерфейсы методов, когда вы будете писать клиентов для кода. - Периодически случается так, что при написании кода вы «нечаянно что-то и где-то» ломаете.

    Смотреть первый пункт следующие 2 слайда Запуск тестов занимает слишком много времени – это неверно, чаще всего юнит-тесты выполняются в течении миллисекунд  придется запустить тысячи тестов, чтобы ощутить эффект от их запуска. Длинные тесты (интеграционные, к примеру) достаточно запускать 1-2 раза в сутки, или делать это со специальной билд-машины. Это не моя работа – тестировать мой код. – А что же является вашей работой? Ваша работа – написание работающего кода. Коммит « buggy »-кода это career limiting move. Вы резко вырастете в глазах коллег (и особенно QA), если ваш код будет содержать очень низкий процент деффектов. Я не знаю точно, как код должен работать, поэтому я не могу написать тест – это когда не очень понятны требования. В этом случае имеет смысл отложить написание тестов и сдеалть прототип, чтобы проверить концепцию. Но он же компилируется! – Не все, что компилируется, правильно работает. Мне платят за за написание кода, а не тестов. – Вероятнее всего вам платят за написание работающего кода, а не на сидение в дебаге , разгребание логов со стектрейсами. Юнит-тесты – это такой же инструмент для написания кода, как IDE или компилятор. Я чувствую вину, оставляя QA без работы. – Не стоит, мы говорим тут о низкоуровневом юнит-тестировании, которое придумано для нас, программистов. QA и так хватает работы с функциональным, acceptance, performance и environmental тестированием. А также всякие валидации, верификации и формальный анализ. Моя компания не позволит запустить юнит-тысты на live- системе. – если мы начинаем говорить о тестах в контексте какого-то окружения, это уже не юнит-тесты. Юнит тесты запускаются на локальной машине с локальной БД или еще лучше с моками и заглушками. Все остальное оставьте QA.

    Это отговорка N1 всех тех, кто не пишет юнит тесты. Конечно же она не верна, когда мы проанализируем, процесс разработки в обоих случаях. Как показывает опыт, без юнит-тестов все вышеперечисленные пункты растут очень быстро по мере роста проектов. Правильное тестирование постоянно «съедает» относительно немного времени, позволяя существенно его экономить на более поздних стадиях проекта по всем вышеперечисленным пунктам. Все помнят вставленные System.out.println(“ Здесь я смотрю, что происходит в этом месте ”) или длинные дебаг-сессии в IDE. При «приучивании» себя к тестам вы можете заметить эффект «привычки» запуска классас с «мини-тестов» в main- е для проверки мелких идей и результатов работы нового кода.

    Есть две модели написания тестов : «тестировать сейчас» или «тестировать потом» . Тестирование не «бесплатно» – на него нужно тратить время. Во втором случае продуктивность может стать отрицательной. Писать тесты в процессе написания основного кода намного Дешевле Проще Быстрее Вернуться к остальным отговоркам на слайд 6

    Что представляет из себя типичный юнит-тест.

    Для начала надо определит, что тестировать. Тестировать надо те вещи, которые наиболее вероятно могут поломаться. Это сразу дает ответ на вопрос, нужно ли тестировать обычные геттеры / сеттеры. Ощущение таких мест будет появляться с опытом. Вот 6 гайдлайнов, которые позволят обратить внимание на основные вещи при тестировании. Используйте свой правый бицепс!

    Чтобы написать правильный код, вы должны ответить на этот вопрос. Если вы не можете ответить на этот вопрос, то написание кода и тестов – пустая трата времени. Если requirements неполны, имеет смысл сделать предположение, что будет верным. Предположения могут быть неверны, но вы будете точно знать, как по вашему пониманию должен вести себя код. Фидбек от юзеров поможет скорректировать неверные предположения.

    Определение граничных условий – одна из самых ценных частей юнит-тестов. Т.к. баги имеют свойства концентрироваться как-раз на них. Наиболее типичные примеры граничных условий: Неверно отформатированные данные Пустые или null- значения Значения, выходящие за допустимые пределы (370 градусов, 32 декабря и т.п) Дупликаты там, где их быть не должно Отсутствие сортировки там, где она должна быть Наиболее простой способ задуматься о граничных условиях – использование акронима CORRECT C onformance – соответствие. name@somewhere.com O rdering – порядок. об этом стоит задумываться в случаях, если коллекции могут сортироваться и результаты работы метода в зависимости от этого могут меняться (к примеру, индексы элементов) R ange – границы – чаще всего стоит проверять значения, выходящие за допустимые пределы, граничные значения и значения внутри диапазона. К примеру для угла [0 : 360] это 1) -10, 370 градусов, 2) 0 и 360 3) любле значение внутри диапазона (0 : 360) R eference – preconditions – это условия, которые должны быть проверены для того, чтобы продолжить исполнение основного кода (к примеру, проверить, что State- машина, необходимая для работы находится в нужном состоянии) . Postconditions – это результаты работы метода. Нужно проверять как прямые результаты, так и возможные косвенные (например, побочный эффект закрытия DataSource – закрытие всех Connection- ов в нем). E xistence – множество потенциальных багов находятся при поисках ответа на вопрос: «Существует ли эта штука?» Вы должны задумываться над тем, что будет, если, к примеру, аргумент типа DataSource , будет null. Многие библиотеки выкидывают IllegalArgumentException при неправильных значениях с соответствующими сообщениями (Assert из Spring- а). Только не пишите при проверке «некоторые значения не установлены). C ardinality – мощность множества. Задачка про бревно (4 части /3 распила, упомянуть про индексы в массивах). Эти ошибки периодически возникают, поэтому хорошая идея проверять, правильно ли «считает» код. Пример проверок на мощность для Top ten list: Can you produce a report when there aren't yet ten items in the list? Can you produce a report when there are no items on the list? Can you produce a report when there is only one item on the list? T ime – время : Относительное (порядок выполнения) – к примеру, подразумевается, что login будет выполнен перед logout- ом, preparedStatement() вызван до execute(). Иногда нужно проверить, что произойдет, если цепочка методов будет вызванна в неправильном порядке (к примеру цепочка фильтров). Сюда также входят проверки таймаутов на ресурсы – могут возникнуть ситуации, когда код будет ждать бесконечно без введения блоков таймаута. Абсолютное (затраченное и текщее время на часах) – про затраченное понятно – алгоритм, который будет выполняться вечно, бесполезен. Насчет второго: если софт работает в различных тайм-зонах, необходимо проверять, правильно ли обрабатываются различные зоны. Concurrency-issues . Я думаю вы понимаете, что дебаггинг таких проблем – особый квест (как минимум про ручной дебаг тут можно забыть). Поэтому крайне важно проверять Race-conditions в ответственных участках кода. Зачастую для этого пишут stress- тесты с массивными объемами данных.

    Некоторые методы могут быть проверены логической инверсией. Например тут, метод извлечения корня из 2-х проверяется возведением результата в квадрат. Вставку в базу можно проверить Select- ом и т.п.

    Зачастую результат выражения можно проверить другими методами. Иногда это позволяет сэкономить время или обойти сложные операции: DAO могут проверяться перехватом SQL- выражения, которое пойдет в JDBC- драйвер и т.п. Вставку значения в кеш на Map- е можно проверить, непосредственно проверив внутреннюю Map- у.

    Некоторые критичные приложения нужно тестировать на различные ошибочные состояния. Не всегда нужно выдергивать кабель из разъема RJ-45 , чтобы проверить обрыв сети. Достаточно вызвать это состояние искусственно. Это можно сделать моками или заглушками.

    Некоторые участки кода необходимо проверять на производительность. Стоит задуматься, какие участки требуют такого тестирования.

    Когда мы говорим автоматические, то подразумеваем автоматический запуск и автоматическую проверку результатов. Поэтому не пишите тестов, которые поломают автоматизацию. Разработчик не должен коммитить код, который поломает автоматизацию исполнения тестов. В идеале он должен сам прогонять все тесты перед коммитом. К сожаленью, это не всегда возможно.

    Хороший тест тестирует ВСЕ , что может сломаться (тут, кстати, сразу и ответ на вопрос: нужно ли тестировать геттеры / сеттеры). Тут есть два экстремума – с одной стороны можно тестировать каждую логическую ветвь, каждое исключение, с другой стороны возможно тестирование только наиболее критичных кусков кода. Что конкретно нужно разработчику – определяет он сам. Тем не менее, первая опция дает намного более качественный код.

    Тесты должны запускаться снова и снова и всегда возвращать одни и те же результаты. Если тесты не обеспеченивают повторяемости теста, у вас наверняка будут неприятные сюрпризы. Одни из самых неприятных сюрпризов – падение тестов при корректном коде Например, это возможно в случае если несколько разработчиков тестируются на одной базе данных.

    Тест должен быть простым и кратким. Он должен быть сфокусирован только на одном аспекте кода и тестировать только его. Это не значит, что внутри него будет только один assert. JUnit не гарантирует порядка запуска тестов. Более того, порядок выполнения одного и того же набора тестов на разных JVM может различаться. Каждый тест должен быть островом.

    К примеру, для google-collections был написан специальный фреймворк для тестировния коллекций. Существую также специальные фреймворки для выполнения наиболее часто используемых операций к примеру, проверка методов equals().

    Когда вы фиксите баг, подумайте: «а нет ли похожих багов в других местах»? Если таковые могут быть, для них должны быть написаны тесты. Не имеет значения, в новом ли коде вы нашли баг или в старом. Если вы не уверены, что написанный тест верен, подстройте так, чтобы он сработал. К примеру, вы тестируете insert записи в DAO, но не уверены, что find- методы работают верно. В этом случае вы можете сделать заглушку, которая будет возвращать, что записи не были добавлены. В итоге, вызов insert должен провалить тест.

    В TDD есть такой паттерн Red-Green-Refactor.

    Favorites, Groups & Events

    JavaTalks.Unit Testing.Part 1 - Presentation Transcript

    1. Часть 1
    2. Что такое Unit -тест
      • Фрагмент кода, написанный разработчиком, для провеки очень маленького, специфичного фрагмента функциональности кода.
    3. Зачем нужно возиться с тестами
      • они делают жизнь проще
      • они делают дизайн приложения лучше
      • они значительно уменьшают время, затрачиваемое на отладку.
    4. Чего мы добиваемся написанием тестов
      • Ответов на вопросы:
      • Делает ли код то, что ожидает от него разработчик?
      • Делает ли он это все время?
      • Можно ли положиться на код?
      • Побочные эффекты:
      • Документирование кода и способов работы с ним
    5. Как писать юнит-тесты
      • Ответить на вопрос: как мы будем тестировать новый метод.
      • Написать тест и тестируемый класс.
      • Запустить тест.
      • Запустить ВСЕ тесты системы.
    6. Типичные отговорки
      • Написание тестов занимает слишком много времени
      • Запуск тестов занимает слишком много времени
      • Это не моя работа – тестировать мой код
      • Я не знаю точно, как код должен работать, поэтому я не могу написать тест
      • Но он же компилируется!
      • Мне платят за за написание кода, а не тестов
      • Я чувствую вину, оставляя QA без работы
      • Моя компания не позволит запустить юнит-тысты на live- системе
    7. Написание тестов занимает слишком много времени
      • Перед тем, как использовать эту отговорку оцените:
      • Сколько времени вы тратите на дебаг кода, написанный вами и вашими коллегами
      • Сколько времени тратится на переработку кода после нахождения крупных багов?
      • Сколько времени тратится на то, чтобы локализовать обнаруженный баг в коде?
    8. Написание тестов занимает слишком много времени
    9.  
    10. Структура теста
      • Создать условия, необходимые для тестов (создать объекты, моки, ресурсы и др.)
      • Настроить моки (если нужно)
      • Вызвать тестируемый метод
      • Проверить, что тестируемый метод ведет себя как ожидается
      • Прибрать за собой (закрыть ресурсы и т.п.)
    11. Right-BICEP
      • Right – верны ли результаты?
      • B – Boundary верны ли граничные условия?
      • I – Inverse можно ли проверить обратные связи?
      • C – Cross-check можно ли проверить результат другими методами?
      • E – Error conditions можно ли вызвать ошибочные состояния искусственно?
      • P – Performance удовлетворительна ли производительность?
    12. Right верны ли результаты
      • Если результаты выполнения кода верны, то как я об этом узнаю?
    13. B – Boundary Проверка граничных условий
      • CORRECT
      • C onformance – верен ли формат значения?
      • O rdering – является ли правильный набор данных упорядоченным?
      • R ange – лежит ли значение в пределах конкретных минимального и максимального значения?
      • R eference – ссылается ли код на что-либо внешнее, что не находится под контролем данного кода? Зависит ли от состояния зависимостей, состояние объекта? Зависит ли код от каких-либо условий.
      • E xistence -
      • C ardinality – количественная проврка результата (нужное ли количество возвращается/используется методами)?
      • T ime – все ли происходит в нужном порядке? В нужное время? В пределах допустимого времени? Правильно ли обрабатываются конкурентные условия?
    14. I - Inverse проверка обратных связей
    15. C - Cross-check проверка результат другими методами
    16. E – Force Error conditions вызов ошибочных состояний
      • Типичные ошибочные состояния
      • Кончилась память
      • Кончилось место на диске
      • Проблемы с синхронизацией времени
      • Доступность и ошибки сетей
      • Система под нагрузкой
      • Ограниченная цветовая палитра
      • Высокое/низкое разрешение экрана
    17. P – Performance параметры производительности
      • Производительность алгоритма
      • Скорость выделения ресурсов
      • Скорость доступа к ресурсам
      • Время обработки запроса
      • Потребляемая память
    18. Свойства хорошего теста
      • A-TRIP:
      • A utomatic – тесты должны запускаться автоматически и проверять результаты автоматически.
      • T horough – тестируйте все, что может сломаться.
      • R epeatable –тесты должны запускаться снова и снова, в любом порядке и всегда возвращать одинаковые результаты.
      • I ndependent – тесты должны быть независимы (от окружения и друг от друга).
      • P rofessional – тест, это код и он должен быть таким же качественным, как и обычный код.
    19. Automatic
      • Не пишите тесты, которые требуют ввода пользователя
      • Если метод требует ресурс (базу данных, соединение по сети), сделайте заклушку или мок для тестирования такого метода
      • Если запуск всех тестов требует длительного времени, то при разработке целесообразно использовать отдельный сервер, который будет запускать такие тесты и рассылать отчеты разработчикам ( Continuous Integration)
    20. Thorough (целостность)
      • Чем больше процент покрытия тестами кода, тем меньше проблем.
      • Баги имеют свойство группироваться в проблемных местах  иногда проще и дешевле переписать такие проблемные места с нуля.
    21. Repeatable
      • Результаты тестов не должны зависеть от чего-то, находящегося под вашим непосредственным контролем (ресурсы, данные из баз данных, внешних систем и т.п.)
      • Используйте моки и заглушки для изоляции теста от таких систем
    22. Independent
      • Убедитесь, что вы тестируете только одну вещь одновременно.
      • Разбивайте сложные операции на несколько более мелких и тестируйте их независимо.
      • Некоторая функциональность может иметь несколько тестов, проверяющих различные ее аспекты (например, тест с применением некорректных значений, тест метода обычном режиме для обработки единичных значений, тест для метода в пакетном режие для массовых операций).
      • Вы не должны зависеть от порядка запуска других тестов.
    23. Professional
      • Используйте все принципы хорошего дизайна: DRY (Don’t Repeat Yourself) , сохраняйте инкапсуляцию, уменьшайте связность компонентов.
      • Не пишите тесты в линейном процедурном стиле, если можно использовать преимущества ООП.
      • Некоторые связанные методы тестирования можно инкапсулировать в отдельные классы.
      • Если необходимо, создавайте фреймворки для тестирования.
      • Не тратьте время на тестирование банальностей (не нужно писать юнит-тесты для get/set- методов).
      • Хорошее покрытие кода ~1:1 (1 строчка кода к одной строчке теста).
    24. Тестирование тестов
      • Не тестируйте тесты – чаще всего в этом нет необходимости.
      • Улучшайте тесты по мере исправления багов.
    25. Как исправлять баги
      • Идентифицировать баг
      • Написать тест, который «поломается» от этого бага, чтобы подтвердить наличие бага.
      • Исправить код так, чтобы тест выполнился.
      • Запустить ВСЕ остальные тесты.
    26. Red-Green-Refactor
    27.  
    28. Общие принципы
      • Тестируйте все, что может сломаться
      • Тестируйте все, что уже сломалось
      • Новый код признается виновным, пока не доказана его невиновность.
      • Тестового кода должно быть как минимум сколько же, сколько и production- кода.
      • Запускайте юнит-тесты локально при каждой компиляции.
      • Запускайте все юнит-тесты перед check-in -ом в репозиторий.
    29. Вопросы, которые стоит задавать при написании кода и тестов
      • Если код выполнился правильно, как я об этом узнаю?
      • Как я собираютсь тестировать это?
      • Что еще может пойти не так?
      • Может ли такая проблема «всплыть» где-нибудь еще?
    30. Спасибо за внимание.
    SlideShare Zeitgeist 2009

    + sgdreadsgdread Nominate

    custom

    279 views, 0 favs, 0 embeds more stats

    Подходы и организация юнит- more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 279
      • 279 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 0
    • Downloads 7
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories

    Tags