Tdd Workbook

137
Разработка Разработка через через тестирование тестирование ( ( Test Driven Development Test Driven Development ) ) [email protected] О вашем вашем инструкторе инструкторе Имя Статусы Контакты 1-2 Рабочие Рабочие материалы материалы Презентация Рабочая среда на ПК 1-3 Учебный Центр Luxoft www.luxoft.ru/edu 1
  • Upload

    -
  • Category

    Business

  • view

    51
  • download

    6

description

Теоретический блок по модульному тестированию, junit и tdd patterns

Transcript of Tdd Workbook

Page 1: Tdd Workbook

РазработкаРазработка черезчерез тестированиетестирование((Test Driven DevelopmentTest Driven Development))[email protected]

ОО вашемвашем инструктореинструкторе

ИмяСтатусыКонтакты

1-2

РабочиеРабочие материалыматериалы

ПрезентацияРабочая среда на ПК

1-3

Учебный Центр Luxoft www.luxoft.ru/edu

1

Page 2: Tdd Workbook

ЦелиЦели курсакурса......

получат общее понятие о целях изадачах тестированияосвоят технологии модульноготестированиянаучатся применять шаблоны приразработке модульных тестов

1-4

По окончании данного курсаслушатели:

ЦелиЦели курсакурса……

ознакомятся с синтаксисом иприобретут опыт практическогоиспользования одной из средтестирования семейства xUnit(JUnit/NUnit)освоят практику разработки черезтестирование

1-5

По окончании данного курсаслушатели:

......ЦелиЦели курсакурса

научаться применять шаблоны TDDполучат практический опытразработки приложения сиспользованием TDD

1-6

По окончании данного курсаслушатели:

Учебный Центр Luxoft www.luxoft.ru/edu

2

Page 3: Tdd Workbook

НеобходимаяНеобходимая подготовкаподготовка

иметь опыт разработки на одном изязыков программирования: Java/C#

1-7

Слушатели должны:

ЗнакомствоЗнакомство

Напишите свое имя на пирамидке, пожалуйстаВаш опыт разработки на Java/С#Ваш опыт работы с JUnitВаш опыт разработки по TDD

1-8

День 1 Модуль 0: ВведениеМодуль 1: Тестирование в разработкеПОМодуль 2: Библиотека модульноготестирования JUnit

День 2 Модуль 3: Test-driven development

Модуль 4: TDD Workshop

РасписаниеРасписание

1-9

Учебный Центр Luxoft www.luxoft.ru/edu

3

Page 4: Tdd Workbook

ОбщиеОбщие рекомендациирекомендации

Отключите телефоныЗадавая вопросы, старайтесьпридерживаться темы обсужденияЕсли у вас возникли вопросы, неотносящиеся к теме, пометьте их, иинструктор будет рад ответить приподходящем случае

1-10

Пожалуйста,

ОрганизацияОрганизация обученияобучения

Время начала и конца занятийПерерывыПитание

1-11

ВопросыВопросы ии ответыответы

1-12

Учебный Центр Luxoft www.luxoft.ru/edu

4

Page 5: Tdd Workbook

ПланПлан курсакурсаМодуль 1: Модульное тестирование

2-13

Тестирование как способ обеспечениякачества продуктаУровни тестированияЦели и задачи модульного тестированияПокрытие кодаУнаследованный кодОрганизационные аспекты тестирования

Качество ПОКачество программного продуктахарактеризуется набором свойств, определяющих, насколько продукт "хорош" с точки зрения заинтересованных сторон

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-14

Качество ПОЗаинтересованными сторонами являются: заказчик продуктаспонсорконечный пользовательразработчикитестировщики продуктаинженеры поддержкисотрудники отделов маркетинга, обучения ипродаж

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-15

Учебный Центр Luxoft www.luxoft.ru/edu

5

Page 6: Tdd Workbook

Качество ПО

Каждый из участников может иметьразличное представление о продукте и отом, насколько он хорош или плох (то естьо том, насколько высоко качествопродукта)

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-16

Качество ПО

Таким образом, постановка задачиобеспечения качества продуктавыливается в задачи:определения заинтересованных лицих критериев качестванахождения оптимального решения, удовлетворяющего этим критериям

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-17

Тестирование: общие понятия

Тестирование является одним изнаиболее устоявшихся способовобеспечения качества разработкипрограммного обеспеченияОно является одним из эффективныхсредств современной системы обеспечениякачества программного продуктаВерификация и валидация ПО

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-18

Учебный Центр Luxoft www.luxoft.ru/edu

6

Page 7: Tdd Workbook

Тестирование: общие понятия

С технической точки зрения,тестирование заключается в:выполнении приложения на некотороммножестве исходных данныхсверке получаемых результатов с заранееизвестными (эталонными) с цельюустановить соответствие различныхсвойств и характеристик приложениязаказанным свойствам

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-19

Тестирование: общие понятия

Тестирование является одной изосновных фаз разработки программногопродукта (наряду с Дизайном приложенияи Разработкой кода)Оно характеризуется достаточно большимвкладом в суммарную трудоемкостьразработки продукта

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-20

Эффективность автоматизации

Широко известна оценка распределениятрудоемкости между фазами созданияпрограммного продукта: 40%-20%-40%*(см. рисунок)

*Котляров В.П., Основы тестирования программного обеспечения

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-21

Оценка распределения трудоемкости истоимости исправления ошибки

Учебный Центр Luxoft www.luxoft.ru/edu

7

Page 8: Tdd Workbook

Эффективность автоматизации

Следовательно, наибольший эффект вснижении трудоемкости может бытьполучен прежде всего на фазах Design иTestingА значит и основные вложения вавтоматизацию или генерацию кодаследует осуществлять, прежде всего, наэтих фазах

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-22

Эффективность автоматизации

Как видно из графика, стоимостьисправления ошибок минимальна настадиях дизайна и разработкиТ.е. было бы неплохо обнаруживатьбольшую часть ошибок до начала фазытестирования

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-23

Эффективность автоматизации

Однако технологии автоматизированноготестирования дизайна (верификациитребований и спецификаций) тольконачинают появлятьсяТрейсинг (дизайна и требований)В то же время, автоматизированноетестирование кода является широкораспространенной практикой

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-24

Учебный Центр Luxoft www.luxoft.ru/edu

8

Page 9: Tdd Workbook

Эффективность автоматизации

Таким образом, процесс тестированиязатрагивает все фазы производства ПО, однако не на всех фазах он может бытьуспешно автоматизирован

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-25

Уровни тестированияРазработка системы, как правило, идет наразличных уровнях:вначале разрабатывается концепция системы, системные требованиязатем архитектура системы, ее разбиение намодулизатем разрабатываются отдельные модули

Процесс верификации также разбивается наотдельные уровни

ТестированиеТестирование –– способспособобеспеченияобеспечения качествакачества продуктапродукта

2-26

ПланПлан курсакурсаМодуль 1: Модульные тесты

2-27

Тестирование как способ обеспечениякачества продуктаУровни тестированияЦели и задачи модульного тестированияПокрытие кодаУнаследованный кодОрганизационные аспекты тестирования

Учебный Центр Luxoft www.luxoft.ru/edu

9

Page 10: Tdd Workbook

Уровни тестированиясистемное тестирование, в ходекоторого тестируется система в целом;интеграционное тестирование, в ходекоторого тестируются группывзаимодействующих модулей и компонентсистемы;модульное тестирование, в ходекоторого тестируются отдельныекомпоненты

УровниУровни тестированиятестирования

2-28

Системное тестированиеСистемное тестирование(System Testing):Основной задачей системноготестирования является проверка какфункциональных, так и нефункциональныхтребований в системе в целом

УровниУровни тестированиятестирования

2-29

Системное тестированиеВ ходе системного тестированиявыявляются следующие дефекты:неверное использование ресурсов системынепредусмотренные комбинации данныхпользовательского уровнянесовместимость с окружениемнепредусмотренные сценарии использованияотсутствующая или невернаяфункциональностьнеудобство использования и т.д.

УровниУровни тестированиятестирования

2-30

Учебный Центр Luxoft www.luxoft.ru/edu

10

Page 11: Tdd Workbook

Системное тестированиеДля минимизации рисков, связанных сособенностями поведения в системы в тойили иной среде, во время тестированиярекомендуется использовать окружениемаксимально приближенное к тому, накоторое будет установлен продукт послевыдачи

УровниУровни тестированиятестирования

2-31

Интеграционное тестированиеИнтеграционное тестирование

(Integration Testing):Интеграционное тестированиепредназначено для проверки связи междукомпонентами, а также взаимодействия сразличными частями системы(операционной системой, оборудованиемлибо связи между различными системами)

УровниУровни тестированиятестирования

2-32

Интеграционное тестированиеИнтеграционное тестирование так жеможет проводиться на различных уровнях:Компонентный: проверяетсявзаимодействие между компонентамисистемы после проведения компонентного(модульного) тестированияСистемный: проверяется взаимодействиемежду разными системами послепроведения системного тестирования

УровниУровни тестированиятестирования

2-33

Учебный Центр Luxoft www.luxoft.ru/edu

11

Page 12: Tdd Workbook

Модульное тестированиеКомпонентное или Модульноетестирование(Component or Unit Testing):Модульное тестирование проверяетфункциональность и ищет дефекты вчастях приложения, которые доступны имогут быть протестированы поотдельности (модули программ, объекты, классы, функции и т.д.)

УровниУровни тестированиятестирования

2-34

Модульное тестированиеОбычно компонентное (модульное) тестирование проводится вызывая код, который необходимо проверить (приподдержке среды разработки)Все найденные дефекты, как правило, исправляются в коде без формального ихописания в системе управления ошибками

УровниУровни тестированиятестирования

2-35

ПланПлан курсакурсаМодуль 1: Модульные тесты

2-36

Тестирование как способ обеспечениякачества продуктаУровни тестированияЦели и задачи модульноготестированияПокрытие кодаУнаследованный кодОрганизационные аспекты тестирования

Учебный Центр Luxoft www.luxoft.ru/edu

12

Page 13: Tdd Workbook

Модульное тестирование

Каждая сложная программная системасостоит из отдельных частей - модулей, выполняющих ту или иную функцию всоставе системыДля того, чтобы удостовериться вкорректной работе всей системы, необходимо вначале протестироватькаждый модуль системы по отдельности

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-37

Модульное тестирование

В случае возникновения проблем притестировании системы в целом этопозволяет проще выявить модули, вызвавшие проблему, и устранитьсоответствующие дефекты в нихТакое тестирование модулей поотдельности получило называниемодульного тестирования(unit testing)

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-38

Определения

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

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-39

Учебный Центр Luxoft www.luxoft.ru/edu

13

Page 14: Tdd Workbook

Определения

Заглушка – объект, предназначенный длясимуляции поведения реального объектаво время тестирования

Тест-план – представляет собой документ, в котором перечислены либо все тестовыепримеры, необходимые для тестированиясистемы, либо часть тестовых примеров, объединенных по определенному признаку

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-40

Определения

Тест-требования – содержат описаниетребований по проверке всех основныхфункций системыДля каждого модуля, подвергаемоготестированию, разрабатывается тестовоеокружение, включающее в себя драйвер изаглушки, готовятся тест-требования итест-планы, описывающие конкретныетестовые примеры

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-41

Цели модульного тестирования

Основная цель модульного тестирования -удостовериться в соответствиитребованиям каждого отдельного модулясистемы перед тем, как будет произведенаего интеграция в состав системы

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-42

Учебный Центр Luxoft www.luxoft.ru/edu

14

Page 15: Tdd Workbook

Задачи модульного тестирования

В ходе модульного тестирования решаютсяследующие основные задачи:Поиск и документирование несоответствийтребованиямПоддержка разработки и рефакторинганизкоуровневой архитектуры системы имежмодульного взаимодействияПоддержка рефакторинга модулейПоддержка устранения дефектов и отладки

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-43

Задачи модульного тестирования

Рефакторинг – процесс полного иличастичного преобразования внутреннейструктуры программы при сохранении еёвнешнего поведения. В его основе лежитпоследовательность небольшихэквивалентных (т.е., сохраняющихповедение) преобразований.

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-44

Задачи модульного тестирования

Поиск и документированиенесоответствий требованиям -классическая задача тестирования, включающая в себя не только разработкутестового окружения и тестовых примеров, но и выполнение тестов, протоколирование результатоввыполнения, составление отчетов опроблемах

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-45

Учебный Центр Luxoft www.luxoft.ru/edu

15

Page 16: Tdd Workbook

Задачи модульного тестирования

Поддержка разработки ирефакторинга низкоуровневойархитектуры системы имежмодульного взаимодействия –модульные тесты помогают выявитьпроблемы в дизайне системы инелогичные или запутанные механизмыработы с модулем

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-46

Задачи модульного тестирования

Поддержка устранения дефектов иотладки сопряжена с обратной связью, которую получают разработчики оттестировщиков в виде отчетов опроблемах

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-47

Задачи модульного тестирования

Подробные отчеты о проблемах, составленные на этапе модульноготестирования, позволяют локализовать иустранить многие дефекты в программнойсистеме на ранних стадиях ее разработкиили разработки ее новойфункциональности

ЦелиЦели ии задачизадачи модульногомодульноготестированиятестирования

2-48

Учебный Центр Luxoft www.luxoft.ru/edu

16

Page 17: Tdd Workbook

Проблемы определения модуля

В силу того, что модули, подвергаемыетестированию, обычно невелики поразмеру, модульное тестированиесчитается наиболее простым (хотя идостаточно трудоемким) этапомтестирования системыОднако, несмотря на внешнюю простоту, смодульным тестированием сопряжены двепроблемы:

ОпределениеОпределение модулямодуля

2-49

Проблемы определения модуля

не существует единых принциповопределения того, что в точности являетсяотдельным модулемтрактовка понятия модульноготестирования - понимается ли под нимобособленное тестирование модуля, работакоторого поддерживается только тестовымокружением, или речь идет о проверкекорректности работы модуля в составе ужеразработанной системы

ОпределениеОпределение модулямодуля

2-50

Традиционное определение

Традиционное определение модуля с точкизрения его тестирования: модуль - это компонент минимальногоразмера, который может быть независимопротестирован в ходе верификациипрограммной системы

В реальности часто возникают проблемы стем, что считать модулем

ОпределениеОпределение модулямодуля

2-51

Учебный Центр Luxoft www.luxoft.ru/edu

17

Page 18: Tdd Workbook

Альтернативные определения

Существует несколько подходов к данномувопросу:модуль - это часть программного кода, выполняющая одну функцию с точкизрения функциональных требованиймодуль - это программный модуль, т.е. минимальный компилируемый элементпрограммной системы

ОпределениеОпределение модулямодуля

2-52

Альтернативные определения

модуль - это задача в списке задачпроекта (с точки зрения его менеджера)модуль - это участок кода, который можетуместиться на одном экране или одномлисте бумагимодуль - это один класс или ихмножество с единым интерфейсоммодуль - это одна функция или метод

ОпределениеОпределение модулямодуля

2-53

Границы модуля

Обычно за тестируемый модульпринимается либо программный модуль(единица компиляции) в случае, еслисистема разрабатывается на процедурномязыке, или класс, если системаразрабатывается на объектно-ориентированном языке

ОпределениеОпределение модулямодуля

2-54

Учебный Центр Luxoft www.luxoft.ru/edu

18

Page 19: Tdd Workbook

Границы модуляВ случае систем, написанных напроцедурных языках, процесстестирования модуля происходитдостаточно просто – для каждого модуляразрабатывается:тестовый драйвер, вызывающий функциимодуля и собирающий результаты ихработынабор заглушек, которые имитируютповедение функций, содержащихся вдругих модулях

ОпределениеОпределение модулямодуля

2-55

Границы модуля

При тестировании объектно-ориентированных систем существует рядособенностей, прежде всего вызванныхинкапсуляцией данных и методов вклассах (декомпозиция класса нарушитпринцип инкапсуляции, согласно которомуобъекты каждого класса должны вестисебя как единое целое с точки зрениядругих объектов)

ОпределениеОпределение модулямодуля

2-56

Границы модуля

Кроме того, более мелкое деление классови использование отдельных методов вкачестве тестируемых модулейнецелесообразно, поскольку длятестирования каждого метода потребуетсяразработка тестового окружения, сравнимого по сложности с уженаписанным программным кодом класса

ОпределениеОпределение модулямодуля

2-57

Учебный Центр Luxoft www.luxoft.ru/edu

19

Page 20: Tdd Workbook

Компонентное тестирование

Процесс тестирования классов как модулейиногда называют компонентнымтестированиемВ ходе такого тестирования проверяетсявзаимодействие методов внутри класса иправильность доступа методов квнутренним данным класса

ОпределениеОпределение модулямодуля

2-58

Компонентное тестирование

На данном этапе возможно обнаружениене только стандартных дефектов(связанных с выходами за границыдиапазона или неверно реализованнымитребованиями), но и специфическихдефектов объектно-ориентированногопрограммного обеспечения

ОпределениеОпределение модулямодуля

2-59

Специфические дефекты ООП

Такими дефектами являются:дефекты инкапсуляции, в результатекоторых, например, сокрытые данныекласса оказываются недоступными длясоответствующих публичных методовдефекты наследования, при наличиикоторых схема наследования блокируетважные данные или методы от классов-потомков

ОпределениеОпределение модулямодуля

2-60

Учебный Центр Luxoft www.luxoft.ru/edu

20

Page 21: Tdd Workbook

Специфические дефекты ООП

дефекты полиморфизма, при которыхполиморфное поведение классаоказывается распространенным не на всевозможные классыдефекты инстанцирования, прикоторых во вновь создаваемых объектахкласса не устанавливаются корректныезначения по умолчанию параметров ивнутренних данных класса

ОпределениеОпределение модулямодуля

2-61

Проблемы тестирования в ООП

Однако, выбор класса в качестветестируемого модуля имеет и рядсопряженных проблем:Определение степени полнотытестирования классаПротоколирование состояний объектов иих измененийТестирование изменений

ОпределениеОпределение модулямодуля

2-62

Проблемы тестирования в ООП

Определение степени полноты тестированиякласса:В том случае, если в качестветестируемого модуля выбран класс, несовсем ясно, как определять степеньполноты его тестированияКлассический критерий полноты покрытия: тесты можно считать полными, есливыполнены все структурные элементы всехметодов, как публичных, так и скрытых

ОпределениеОпределение модулямодуля

2-63

Учебный Центр Luxoft www.luxoft.ru/edu

21

Page 22: Tdd Workbook

Проблемы тестирования в ООП

Однако существует альтернативныйподход к тестированию класса: всепубличные методы должны предоставлятьпользователю данного классасогласованную схему работыВ этом случае достаточно проверитьтипичные корректные и некорректныесценарии работы с данным классом

ОпределениеОпределение модулямодуля

2-64

Проблемы тестирования в ООП

Протоколирование состояний объектов и ихизменений:Некоторые методы класса предназначеныне для выдачи информации пользователю, а для изменения внутренних данныхобъекта класса

ОпределениеОпределение модулямодуля

2-65

Проблемы тестирования в ООП

Значение внутренних данных объектаопределяет его состояние в каждыйопределенный момент времени, а вызовметодов, изменяющих данные, изменяет исостояние объектаПри тестировании классов необходимопроверять, что класс адекватно реагируетна внешние вызовы в любом из состояний

ОпределениеОпределение модулямодуля

2-66

Учебный Центр Luxoft www.luxoft.ru/edu

22

Page 23: Tdd Workbook

Проблемы тестирования в ООП

Однако, зачастую из-за инкапсуляцииданных невозможно определитьвнутреннее состояние классапрограммными способами внутри драйвераАвтоматизированное тестирование в этомслучае может лишь определить, по всемли выявленным состояниямосуществлялись переходы и все ливозможные реакции проверялись

ОпределениеОпределение модулямодуля

2-67

Проблемы тестирования в ООП

Тестирование изменений:В результате рефакторинга только одногокласса, как правило, не меняется еговнешний интерфейс с другими классами(интерфейсы меняются при рефакторингесразу нескольких классов)

ОпределениеОпределение модулямодуля

2-68

Проблемы тестирования в ООП

В результате обычных эволюционныхизменений системы у класса можетменяться внешний интерфейс:по формальным признакам –изменяютсяимена и состав методов, их параметрыпо функциональным признакам – присохранении внешнего интерфейса меняетсялогика работы методов (contract)

ОпределениеОпределение модулямодуля

2-69

Учебный Центр Luxoft www.luxoft.ru/edu

23

Page 24: Tdd Workbook

Проблемы тестирования в ООП

Для проведения модульного тестированиякласса после таких изменений потребуетсяизменение драйвера и, возможно, заглушекНо только модульного тестирования вданном случае недостаточно, необходимотакже проводить и интеграционноетестирование данного класса вместе совсеми классами, которые связаны с ним поданным или по управлению

ОпределениеОпределение модулямодуля

2-70

Проблемы тестирования в ООП

Связь по управлению реализуется путемвызова одного модуля из другого. Вызванный модуль после завершениясвоей работы возвращает управлениевызвавшему его модулю.Связь по данным реализуется двумяспособами:использование параметров при вызовемодулейиспользование общих областей данных

ОпределениеОпределение модулямодуля

2-71

Определение отладкиОтладка — этап разработкикомпьютерной программы, на которомобнаруживают, локализуют и устраняютошибкиЧтобы понять, где возникла ошибка, приходится:узнавать текущие значения переменныхвыяснять, по какому пути выполняласьпрограмма

ОтличияОтличия модульногомодульноготестированиятестирования ии отладкиотладки

2-72

Учебный Центр Luxoft www.luxoft.ru/edu

24

Page 25: Tdd Workbook

Технологии отладкиСуществуют две взаимодополняющиетехнологии отладки:Использование отладчиков — программ, которые включают в себяпользовательский интерфейс дляпошагового выполнения программы, состановками на указанных строкахисходного кода или при выполненииопределённого условия

ОтличияОтличия модульногомодульноготестированиятестирования ии отладкиотладки

2-73

Технологии отладкиВывод текущего состояния программы спомощью расположенных в критическихточках программы операторов вывода —на экран, принтер, или в файл (выводотладочных сведений в файл называетсяжурналированием)

ОтличияОтличия модульногомодульноготестированиятестирования ии отладкиотладки

2-74

Проблемы при отладкеОднако использование отладки сопряжено срядом проблем:Отладка метода, глубоко «закопанного» вбольшом приложении, иливоспроизведение тестовой ситуациизачастую становятся чрезвычайнотрудоемкими

ОтличияОтличия модульногомодульноготестированиятестирования ии отладкиотладки

2-75

Учебный Центр Luxoft www.luxoft.ru/edu

25

Page 26: Tdd Workbook

Проблемы при отладкеИногда не удается проверить только чтонаписанный код, потому что он еще нигдеи никак не используетсяВ некоторых ситуациях программистыдаже разрабатывают специальныеутилиты, позволяющие отладить тот илииной компонент отдельно от всей системы

ОтличияОтличия модульногомодульноготестированиятестирования ии отладкиотладки

2-76

Преимущества модульных тестовПри использовании модульных тестовподобных проблем просто не возникает:Если нужно что-нибудь проверить –пишется соответствующий тестТесты представляют собой практическиидеальную отладочную среду: онинаходятся полностью под контролемпрограммиста и позволяют вызвать любойкод в широком диапазоне условий

ОтличияОтличия модульногомодульноготестированиятестирования ии отладкиотладки

2-77

Преимущества модульных тестовДля большинства ошибок, найденных примодульном тестировании, отладка вообщене требуется, поскольку точно известны: место их возникновения (код, который былнаписан только что)условия воспроизведения (тест, которыйсейчас отлаживается)

ОтличияОтличия модульногомодульноготестированиятестирования ии отладкиотладки

2-78

Учебный Центр Luxoft www.luxoft.ru/edu

26

Page 27: Tdd Workbook

Фазы тестированияФормально, процесс тестирования можноразделить на следующие фазы:планированиеразработка набора тестоввыполнение тестов и сбор статистики,

каждая из которых характеризуетсяопределенным набором активностей

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-79

Фаза планированияНа этапе планирования формируются общиепринципы тестирования в проекте:степень полноты и охвата тестированияисточники входных и выходных данныхтехнологии проверки результатов и форматих записитребования к завершению тестирования

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-80

Фаза планированияА так же анализируются свойства каждого измодулей:функциональные требованиядополнительные требования (напр. системные)характеристики входных и выходныхданныхопределение состояний модуля (еслимодуль можно представить в видеконечного автомата)

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-81

Учебный Центр Luxoft www.luxoft.ru/edu

27

Page 28: Tdd Workbook

Фаза планированияПосле анализа требований к модулям, возможно возникнет необходимость внестикорректировки в общие принципытестированияПосле этого фазу планирования можносчитать оконченной

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-82

Фаза разработки тестовВ ходе этапа разработки тестов должныбыть решены следующие задачи:разработка архитектуры тестовых наборовразработка тестовых сценариев (test-case) и тестовых наборов (test-suite)разработка нефункциональных тестов, (напр., основанных на архитектуре)составление спецификаций тестов(документирование)

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-83

Фаза разработки тестовтестовый сценарий – определениенабора входных данных теста, условийвыполнения и ожидаемых результатов, указанных с целью оценки некоторогоаспекта тестируемого элементатестовый набор – набор тестовыхсценариев, объединенных по какому-либопризнаку (напр., тестирующих конкретныймодуль или его часть егофункциональности)

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-84

Учебный Центр Luxoft www.luxoft.ru/edu

28

Page 29: Tdd Workbook

Фаза разработки тестовВ ходе разработки тестовых сценариев также выполняются следующие задачи:формируются тестовые наборы данныхсоздается тестовое окружениеосуществляется интеграция тестовогоокружения с тестируемым модулем

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-85

Фаза выполнения и анализаПосле того, как все тесты реализованы, они выполняются в ручном илиавтоматическом режимеВне зависимости от вида тестирования входе этого этапа решаются две задачи: выполнение тестовых примеровсбор и анализ результатов тестирования

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-86

Фаза выполнения и анализаСбору подлежит следующая информация:результат выполнения каждого тестовогосценария (прошел/не прошел)информация об информационномокружении системы в случае, если тест непрошелинформация о ресурсах, которыепотребовались для выполнения тестовогопримера

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-87

Учебный Центр Luxoft www.luxoft.ru/edu

29

Page 30: Tdd Workbook

Фаза выполнения и анализаПо результатам анализа этой информациипроизводится изменение требований, программного кода, тестов или тестовогоокруженияЭтапы разработки (доработки), реализациии выполнения тестов продолжаются до техпор, пока не будет достигнут критерийзавершения модульного тестирования(напр., 90% покрытие тестами исходногокода)

ОрганизацияОрганизация модульногомодульноготестированиятестирования

2-88

Общие понятияКлассы (модули), как правило, редкобывают полностью изолированными, ииспользуют в своей работе другие классыНапример, слой бизнес логики (BusinessLogic Layer) часто работает с другимиобъектами бизнес логики или обращаетсяк слою доступа к данным (Data Access Layer)

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-89

Общие понятияВ таких случаях на помощь приходятmock-объекты (заглушки), предназначенные для симуляцииповедения реальных объектов во времятестированияПонятие mock-объект может обозначатькак любой из видов заглушек (Test Doublers, тестовых дублеров), так иконкретный их вид – mock-объекты

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-90

Учебный Центр Luxoft www.luxoft.ru/edu

30

Page 31: Tdd Workbook

Общие понятияВсе тест-дублеры делятся на 4 группы*:

dummy-объектыfake-объектыstub-объектыmock-объекты

*Gerard Meszaros – “XUnit Test Patterns”, Martin Fawler – “Refactoring: Improving the Design of Existing Code”

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-91

Dummy-объектыDummy – пустые объекты, которыепередаются в вызываемые внутренниеметоды, но не используются(предназначены лишь для заполненияпараметров методов)

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-92

Dummy-объектыpublic void testInvoice_addLineItem() {

final int QUANTITY = 1;Product product = new Product(getUniqueNumberAsString(),

getUniqueNumber());City city = new City(“Vladivostok", “Russia”);Address address = new Address(“Lenin St, 12", city, “650243");Customer customer= new Customer(getUniqueNumberAsString(),

getUniqueNumberAsString(), address);Invoice inv = new Invoice(customer);// Вызовinv.addItemQuantity(product, QUANTITY);// ПроверкаList lineItems = inv.getLineItems();assertEquals("number of items", lineItems.size(), 1);LineItem actual = (LineItem)lineItems.get(0);LineItem expItem = new LineItem(product, QUANTITY);assertLineItemsEqual("",expItem, actual);

}

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-93

Учебный Центр Luxoft www.luxoft.ru/edu

31

Page 32: Tdd Workbook

Dummy-объектыpublic void testInvoice_addLineItem() {

final int QUANTITY = 1;Product product = new Product(“Dummy product name”,

getUniqueNumber());Invoice inv = new Invoice(new DummyCustomer);// Вызовinv.addItemQuantity(product, QUANTITY);// ПроверкаList lineItems = inv.getLineItems();assertEquals("number of items", lineItems.size(), 1);LineItem actual = (LineItem)lineItems.get(0);LineItem expItem = new LineItem(product, QUANTITY);assertLineItemsEqual("",expItem, actual);

}

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-94

Dummy-объекты

public class DummyCustomer implements ICustomer {

public DummyCustomer() {// Конструктор оставляем пустым – никакой инициализации

не требуется}

public int getTimeZone() {throw new RuntimeException(“Этот метод не должен быть

вызван!”);}

}

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-95

Stub-объектыStub:объекты, которые предоставляют заранеезаготовленные ответы на вызовы во времявыполнения теста и обычно не отвечающие нина какие другие вызовы, которые нетребуются в тестетакже могут запоминать какую-тодополнительную информацию о количествевызовов, параметрах и возвращать их потомтесту для проверки

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-96

Учебный Центр Luxoft www.luxoft.ru/edu

32

Page 33: Tdd Workbook

Stub-объектыВыделяют несколько видов stub’ов, взависимости от целей применения:Responder (ответчик)используется для эмуляции корректногоповедения объектакак правило, используется в happy-path-тестахиспользуется, когда реальный объект ещене реализован, либо недоступен вдевелоперском окружении

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-97

Stub-объектыSaboteur (диверсант)используется для эмуляции некорректногоповедения объектапризван всеми возможными способамивызвать «крах» системы, выдаваянекорректные значения, исключения и т.п. вне зависимости от получаемых входныхданныхиспользуется для тестирования обработкиразличных отказов

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-98

Stub-объектыTemporary stub (временная заглушка)используется для замены еще нереализованного объектакак правило, возвращает hardcoded-значениязаменяется реальным объектом, как толькоэто становится возможным, либо сампостепенно становится этим объектам, постепенно получая функциональноенаполнение

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-99

Учебный Центр Luxoft www.luxoft.ru/edu

33

Page 34: Tdd Workbook

Stub-объектыEntity chain snippingиспользуется для замены сложной системывзаимодействующих объектов однимупрощает процедуру инициализациитестового окруженияделает тесты более понятными

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-100

Stub-объектыВ зависимости от реализации, stub’ыбывают:Hard-coded stub (статические)на любые запросы выдают одно и то жежестко прописанное значениекак правило, пишутся для конкретноготеста, либо их небольшого набора

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-101

Stub-объектыConfigurable stub (конфигурируемые)используются для того, чтобы для каждоготеста не писать свой статический stubтест конфигурирует stub во время своейинициализации

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-102

Учебный Центр Luxoft www.luxoft.ru/edu

34

Page 35: Tdd Workbook

Fake-объектыК сожалению, редко можно обойтисьпростыми dummy- и stub-объектамиИногда, тестируемый метод можетобращаться к базе данных, web-сервисам, или файловой системеВ этом случае, наш объект должен уметь«симулировать» требуемые действия, выполняя более простой код (напр., сохранять данные в памяти вместо БД)

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-103

Fake-объектыFake – объекты, имеющие работающиереализации, но в таком виде, которыйделает их неподходящими для production-кодаПримеры fake-объектов:

Fake database – реальная БД заменяетсяаналогичным по функциональности, ноболее «легким» аналогом (который даствыигрыш при тестировании, но невыдержит production нагрузки)

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-104

Fake-объектыIn-memory database – реальная БДзаменяется набором HashTable’s, либо еёнебольшим «слепком», размещаемым впамяти на время выполненияFake web-service – реальный web-сервисзаменяется локальной реализацией, возвращающей определенное значение(или набор значений), что позволяетвыполнять тесты вне зависимости отдоступности сервиса

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-105

Учебный Центр Luxoft www.luxoft.ru/edu

35

Page 36: Tdd Workbook

Mock-объектыMock:объекты, которые заменяют реальныйобъект в условиях теста и позволяютпроверять вызовы своих членов как частьсистемы или модульного тестасодержат заранее запрограммированныеожидания вызовов, которые они должныполучитьприменяются в основном для interaction testing

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-106

Mock-объектыВо время инициализации теста, мысоздаем и настраиваем mock-объект(определяем возвращаемые значения, ожидаемые вызовы и их аргументы)Во время выполнения, mock-объектсравнивает получаемые вызовы изначения с ожидаемыми, и «заваливает»тест при несовпаденииПо окончании теста проверяется наличиеметодов, которые не были вызваны

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-107

Mock-объектыРассмотрим пример: при удалениипользователя, сообщение об этом должнопоявляться в логеpublic void TestRemoveUser() {

CommonUser expectedCU = createCommonUser();UserManagementFacade facade =

new UserManagementFacadeImpl();facade.removeUser(expectedCU.getUserNumber());assert.False(“User should not exist after removing”,

facade.userExists(expectedCU.getUserNumber()));}

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-108

Учебный Центр Luxoft www.luxoft.ru/edu

36

Page 37: Tdd Workbook

Mock-объектыpublic void TestRemoveUser_Mock() {

CommonUser expectedCU = createCommonUser();MockAuditLog mockLog = new MockauditLog();mockLog.setExpectedLogMessage(helper.getDate(),

helper.TEST_USER_NAME,helper.USER_REMOVE_ACTION_CODE,

expectedCU.getUserNumber);mockLog.setExpectedCallsNumber(1);UserManagementFacade facade = new

UserManagementFacadeImpl();facade.setAuditLog(mockLog);facade.removeUser(expectedCU.getUserNumber());assert.False(“User should not exist after removing”,

facade.userExists(expectedCU.getUserNumber()));mockLog.verify();

}

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-109

Mock-объектыРеализация метода LogMessagemock-объекта

public void LogMessage(Data actualDate, String actualUser,String actualActionCode,int actualUserNumber) {

actualCallsNumber++;Assert.assertEquals(“date”, expectedDate, actualDate);Assert.assertEquals(“user”, expectedUser, actualUser);Assert.assertEquals(“action code”, expectedActionCode,

actualActionCode);Assert.assertEquals(“number”, expectedNumber,

actualNumber);}

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-110

Подходы к модульному тестированиюState-based testing – подход, прикотором проверяется состояние объектапосле прохождение unit-тестаInteraction testing – подход кмодульному тестированию, при которомтестируется взаимодействие объектов, поведение методов, последовательностьих вызовов и т.п.

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-111

Учебный Центр Luxoft www.luxoft.ru/edu

37

Page 38: Tdd Workbook

Подходы к модульному тестированиюВ state-based testing нас интересует, вкакое состояние перешел объект послевызова тестируемого метода, или чтовернул наш метод и правилен ли этотрезультатПодобные проверки проводятся припомощи вызова методов класса Assertразличных unit-тест фреймворков: Assert.AreEqual(), Assert.IsNull() и т.д.

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-112

Подходы к модульному тестированиюВ interaction testing нас интересует преждевсего не статическое состояние объекта, ате динамические вызовы методов, которыепроисходят у него внутриВ этом случае используют специальныеmock-фреймворки, содержащиеопределенные конструкции для записиожиданий и их последующей проверки(методы Verify(), VerifyAll() и т.п.)

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-113

Подходы к модульному тестированиюMartin Fawler называет эти два подходаклассическим (classical) и мокистским(mockist) unit-тестированием и делитпрограммистов на предпочитающихпервый и второй подходыНа самом деле, иногда просто удобнеепроверить состояние объекта, а иногда –его взаимодействие с другими объектами

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-114

Учебный Центр Luxoft www.luxoft.ru/edu

38

Page 39: Tdd Workbook

Подходы к модульному тестированиюЭти два подхода прекрасно уживаютсявместе, когда вы понимаете, о чем идетречь, и что именно вы хотите сейчаспроверитьТочно так же, как уживаются в одномтесте mock’и и stub’ы

ИспользованиеИспользование mockmock-- ииstubstub--объектовобъектов

2-115

ПланПлан курсакурсаМодуль 1: Модульные тесты

2-116

Тестирование как способ обеспечениякачества продуктаУровни тестированияЦели и задачи модульного тестированияПокрытие кодаУнаследованный кодОрганизационные аспекты тестирования

Понятие полноты системы тестовОдной из оценок качества системы тестовявляется полнота – величина той частифункциональности системы, котораяпроверяется тестамиПолная система позволяет утверждать, что система реализует всюфункциональность, указанную втребованиях

ПонятиеПонятие покрытияпокрытияпрограммногопрограммного кодакода

2-117

Учебный Центр Luxoft www.luxoft.ru/edu

39

Page 40: Tdd Workbook

Понятие полноты системы тестовКроме того, это позволяет утверждать, чтосистема не реализует никакой другойфункциональностиСтепень покрытия программного кодатестами – важный количественныйпоказатель, позволяющий оценитькачество как системы тестов, так итестируемой системы

ПонятиеПонятие покрытияпокрытияпрограммногопрограммного кодакода

2-118

Понятие полноты системы тестовОдним из наиболее часто используемыхметодов определения полноты системытестов является определение отношенияколичества тест-требований, для которыхсуществуют тесты, к общему количествутест-требованийВ данном случае речь идет о покрытиитестами тест-требований

ПонятиеПонятие покрытияпокрытияпрограммногопрограммного кодакода

2-119

Понятие полноты системы тестовВ качестве единицы измерения степенипокрытия здесь выступает процент тест-требований, для которых существуюттестыПокрытие требований позволяет оценитьстепень полноты системы тестов поотношению к функциональности системы, но не позволяет оценить полноту поотношению к ее программной реализации

ПонятиеПонятие покрытияпокрытияпрограммногопрограммного кодакода

2-120

Учебный Центр Luxoft www.luxoft.ru/edu

40

Page 41: Tdd Workbook

Понятие покрытия кодаОдна и та же функция может бытьреализована при помощи совершенноразличных алгоритмов, требующихразного подхода к организациитестированияДля более детальной оценки полнотысистемы тестов анализируется покрытиепрограммного кода, называемое такжеструктурным покрытием

ПонятиеПонятие покрытияпокрытияпрограммногопрограммного кодакода

2-121

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

ПонятиеПонятие покрытияпокрытияпрограммногопрограммного кодакода

2-122

Уровни покрытия кода

Существует несколько различных способовизмерения покрытия, основные из них:покрытие операторовпокрытие условийпокрытие путейпокрытие функцийпокрытие вход/выход

УровниУровни покрытияпокрытия

2-123

Учебный Центр Luxoft www.luxoft.ru/edu

41

Page 42: Tdd Workbook

Покрытие операторов

Для обеспечения полного покрытияпрограммного кода на уровне операторовнеобходимо, чтобы в результатевыполнения тестов каждый оператор былвыполнен хотя бы один разПеред началом тестирования необходимовыделить переменные, от которых зависитвыполнение различных ветвей условий ициклов в коде – управляющие входныепеременные

УровниУровни покрытияпокрытия

2-124

Покрытие операторов

if (i == 0 || i == 101) {if (showMessage) {

MessageBox.Show(“Входной параметр имеетнедопустимое значение ” + i.ToString());

} else {System.Out.Writeln(“Входной параметр имеетнедопустимое значение ” + i.ToString());

}return -1;

}

УровниУровни покрытияпокрытия

2-125

Покрытие операторов

Для полного покрытия по операторам, достаточно двух тестов:

i = 0, showMessage = truei = 0, showMessage = false

Легко заметить, что при этом, тесты непокрывают всей функциональности (непротестировано поведение системы приi = 101)

УровниУровни покрытияпокрытия

2-126

Учебный Центр Luxoft www.luxoft.ru/edu

42

Page 43: Tdd Workbook

Покрытие операторов

Также проблемы этого метода покрытияможно увидеть и на примерах другихуправляющих структурНапример, при проверке циклов do …while – при данном уровне покрытиядостаточно выполнение цикла только одинраз, при этом метод совершеннонечувствителен к логическим операторам|| и &&

УровниУровни покрытияпокрытия

2-127

Покрытие операторов

Другой особенностью данного методаявляется зависимость уровня покрытия отструктуры программного кодаРассмотрим простейший пример:

if (condition)MethodA();

elseMethodB();

УровниУровни покрытияпокрытия

2-128

Покрытие операторов

Если MethodA() содержит 99 операторов, а MethodB() — один оператор, тоединственного теста, устанавливающегоcondition в true, будет достаточно длядостижения 99%-го уровня покрытияПри этом аналогичный тестовый пример, устанавливающий значение condition вfalse, даст слишком низкий уровеньпокрытия (1%)

УровниУровни покрытияпокрытия

2-129

Учебный Центр Luxoft www.luxoft.ru/edu

43

Page 44: Tdd Workbook

Покрытие условий

Для обеспечения полного покрытияусловий необходимо:каждая точка входа и выхода в программеи во всех ее функциях должна бытьвыполнена по крайней мере один развсе логические выражения в программедолжны принять каждое из возможныхзначений хотя бы один раз

Таким образом, для покрытия по веткамтребуется как минимум два теста

УровниУровни покрытияпокрытия

2-130

Покрытие условий

if (i == 0 || i == 101) {if (showMessage) {

MessageBox.Show(“Входной параметр имеетнедопустимое значение ” + i.ToString());

} else {System.Out.Writeln(“Входной параметр имеетнедопустимое значение ” + i.ToString());

}return -1;

}

УровниУровни покрытияпокрытия

2-131

Покрытие условий

Для покрытия предыдущего примера кодапо ветвям потребуется уже три тестаЭто связано с тем, что первый условныйоператор if имеет неявную ветвь –пустую ветвь elseДля обеспечения покрытия по ветвямнеобходимо покрывать и пустые ветви

УровниУровни покрытияпокрытия

2-132

Учебный Центр Luxoft www.luxoft.ru/edu

44

Page 45: Tdd Workbook

Покрытие условий

Особенность данного уровня покрытиязаключается в том, что на нем могут неучитываться логические выражения, значения которых получаются вызовомметодовРассмотрим пример кода:

if (condition1 && (condition2 || Method()))statement1;

elsestatement2;

УровниУровни покрытияпокрытия

2-133

Покрытие условий

Полное покрытие условий может бытьдостигнуто при помощи двух тестов:

condition1 = true, condition2 = truecondition1 = false, condition2 = true/false

В обоих случаях не происходит вызоваметода Method() (хотя покрытие будетполным)Для его проверки необходимо добавитьеще один тест:

condition1 = true, condition2 = false

УровниУровни покрытияпокрытия

2-134

Покрытие путей

В данном случае считаются все пути, которые выполняются в процессе работытестируемого методаПуть - уникальная последовательностьвыполнения операторов, с учетомусловных операторовМетод, содержащий в себе N условий, имеет 2^N путейМетод, содержащий цикл, может иметьбесконечное число путей

УровниУровни покрытияпокрытия

2-135

Учебный Центр Luxoft www.luxoft.ru/edu

45

Page 46: Tdd Workbook

Покрытие путей

Т.о. в большинстве случаев 100%-епокрытие путей обеспечить невозможноДля решения этой проблемы, может бытьприменен метод покрытия основных(базисных, линейно-независимых) путейОсновные пути – минимальный наборпутей, комбинация которых можетобеспечить все возможные путивыполнения метода

УровниУровни покрытияпокрытия

2-136

Покрытие путей

Число таких путей равно числу уникальныхусловных операторов, увеличенное на 1Рассмотрим следующий пример:

if (condition1)statement1;

if (condition2)statement2;

if (condition3)statement3;

УровниУровни покрытияпокрытия

2-137

Покрытие путей

Для достижения 100% покрытия основныхпутей, нам потребуется 4 линейно-независимых путиПервый путь выбирается случайно (пустьэто будет путь, когда все условныевыражения принимают значение true)Оставшиеся пути получаются поочередныминвертированием одного из условныхвыражений первого пути

УровниУровни покрытияпокрытия

2-138

Учебный Центр Luxoft www.luxoft.ru/edu

46

Page 47: Tdd Workbook

Покрытие путей

Таким образом, получаем четыре основныхпути, которые необходимо покрыть:

УровниУровни покрытияпокрытия

2-139

condition1 condition2 condition3

Path 1 true true true

Path 2 false true true

Path 3 true false true

Path 4 true true false

Покрытие путей

В случае наличия циклов, можетиспользоваться следующий подход:выделяем классы путей (к одному классуможно отнести пути, отличающиесяколичеством итераций в конкретном цикле)класс считается покрытым, если покрытхотя бы один путь из него100% покрытие достигнуто, если покрытывсе классы путей

УровниУровни покрытияпокрытия

2-140

Покрытие функцийПокрытие функций – каждая лифункция тестируемого модуля являетсявыполненной хотя бы один разЯвляется одним из самых простых методоврасчета покрытия, и дает довольно общеепредставление о качестве тестируемогомодуляС одной стороны, данное покрытиеговорит нам о том, что тестами покрытвесь реализованный функционал модуля

УровниУровни покрытияпокрытия

2-141

Учебный Центр Luxoft www.luxoft.ru/edu

47

Page 48: Tdd Workbook

Покрытие функций

С другой стороны, оно не гарантирует намадекватное поведение модуля, поскольку: не проверяется реакция функций на всевозможные входные параметрыне проверяется реакция системы на всевозможные возвращаемые функциейзначения

УровниУровни покрытияпокрытия

2-142

Покрытие вход/выход

Покрытие вход/выход – все ливозможные варианты вызова функций ивозврата из них были выполненыНа данном уровне обеспечиваетсятестирование как самих функций (всевозможные варианты вызова), так и ихвзаимодействие в составе модуля (всевозможные варианты возврата)

УровниУровни покрытияпокрытия

2-143

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

АнализАнализ покрытияпокрытия

2-144

Учебный Центр Luxoft www.luxoft.ru/edu

48

Page 49: Tdd Workbook

Цели и задачи анализаВ идеальном случае при полном покрытиифункциональных требований должнополучаться 100% покрытие кодаОднако на практике такое происходиттолько в случае очень простого кодаПричины «недопокрытия» кода могут бытьразличными

АнализАнализ покрытияпокрытия

2-145

Причины плохого покрытия кодаНедостатки в формировании тестов, основанных на требованияхтестовый набор должен быть дополненнедостающими тестами

Неадекватности в требованияхтребования должны бытьмодифицированы, после чего разработаныи выполнены дополнительные тесты, покрывающие новые требования

АнализАнализ покрытияпокрытия

2-146

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

Дезактивируемый код – код, работающий только в определенныхконфигурациях окружения

АнализАнализ покрытияпокрытия

2-147

Учебный Центр Luxoft www.luxoft.ru/edu

49

Page 50: Tdd Workbook

Причины плохого покрытия кодаДезактивируемый коддля такого кода должна быть установленанормальная эксплуатационная среда, вкоторой он выполняетсянаписаны тесты, покрывающие егонаписаны тесты, проверяющие, что данныйкод не может быть преднамеренновыполнен в других конфигурациях

АнализАнализ покрытияпокрытия

2-148

Причины плохого покрытия кодаИзбыточные условияпример такого условия – выражение!b || (a && b)

при b = false, значение переменной a неимеет значения, т.е. условие избыточно ивторая его часть не будет проверяться

Защитный код

АнализАнализ покрытияпокрытия

2-149

Причины плохого покрытия кодаЗащитное программирование - этометод организации программного кодатаким образом, чтобы при работе системыпоследствия проявления дефектов в нейне приводили к сбоям, отказам и авариям(проверка входных данных, обработкаисключений и т.д.)

АнализАнализ покрытияпокрытия

2-150

Учебный Центр Luxoft www.luxoft.ru/edu

50

Page 51: Tdd Workbook

Причины плохого покрытия кодаНапример, это может быть ветка defaultв операторе выбора switchВходное условие оператора switch можетпринимать определенные значенияКак следствие, ветка default, возможноникогда не будет выполнена

АнализАнализ покрытияпокрытия

2-151

Причины плохого покрытия кодаЗащитное программирование, как правило, не дает нам никакой информации о том, где в системе находится дефектЕго нельзя рассматривать как заменутестирования - эти два аспекта разработкисистем лишь дополняют друг друга

АнализАнализ покрытияпокрытия

2-152

Причины плохого покрытия кодаТакже существуют случаи, когдамодульное тестирование кода сильнозатруднено, либо вообще невозможно:генерация случайных чиселсложные математические алгоритмыпараллельные алгоритмы

АнализАнализ покрытияпокрытия

2-153

Учебный Центр Luxoft www.luxoft.ru/edu

51

Page 52: Tdd Workbook

Результаты анализаТаким образом, отсутствие покрытиякаких-либо участков кода можетявляться сигналом к переработке тестов, кода, а иногда – и требованийС другой стороны, 100% покрытие кода негарантирует нам, что в приложении нетошибок

АнализАнализ покрытияпокрытия

2-154

Результаты анализаПомните, что тесты пишутся дляповышения качества кода и лучшегоего понимания, а не для повышенияпоказателей метрик

АнализАнализ покрытияпокрытия

2-155

ПланПлан курсакурсаМодуль 1: Модульные тесты

2-156

Тестирование как способ обеспечениякачества продуктаУровни тестированияЦели и задачи модульного тестированияПокрытие кодаУнаследованный кодОрганизационные аспекты тестирования

Учебный Центр Luxoft www.luxoft.ru/edu

52

Page 53: Tdd Workbook

Legacy-кодПричины появления legacy-код:Появление новых технологий: существуют огромные программныекомплексы, написанные на языке C++, который считался передовым всего десятьлет назад

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-157

Legacy-кодРазвитие существующих технологий: частые изменения в языках и платформахJava/C# очень быстро приводят кпоявлению унаследованных решений, поскольку то, что когда-то считалосьноваторским, превращается внеподдерживаемый, устаревший код

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-158

Legacy-кодБурное развитие системы: зачастую, программисты сосредоточивают усилияименно на реализации новыхвозможностей программного обеспечения –применяются новые технологии, носуществующий функционал при этом несовершенствуется

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-159

Учебный Центр Luxoft www.luxoft.ru/edu

53

Page 54: Tdd Workbook

Legacy-кодИтак, нужно ли писать тесты для legacy-кода?Да, нужно, но только если вы собираетесьего изменять:

Unit-тесты позволят вам понять, какработает кодUnit-тесты позволят вам убедиться, чтоваши изменения не нарушили логикуработы модуля

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-160

Legacy-кодВаша цель – получить тесты, которымможно доверятьЕсли функция полностью покрытамодульными тестами, то вы не будетебоятся ее изменить или даже полностьюпереписать

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-161

Избавление от зависимостейКак правило, такой код имеет множествозависимостей: подключает различные lib иdll, посылает сообщения в сеть или другимкомпонентам, отображает что-то в GUI ит.д.Итак, первое, что нам необходимо сделать– это избавиться от этих зависимостейДля этого можно использовать ужезнакомые нам mock- и stub-объекты

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-162

Учебный Центр Luxoft www.luxoft.ru/edu

54

Page 55: Tdd Workbook

Dependency injectionЗачастую, этих средств недостаточно инеобходимо проводить рефакторингЗдесь на помощь нам приходит паттерн“Dependency injection”Суть его заключается в следующем: есликласс А использует класс В, то необходимосделать так, чтобы конкретная реализациякласса В передавалась классу А “извне”, ане определялась внутри него

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-163

Проблемы покрытия legacy-кодаПосле того, как все связи с внешниммиром у класса или функции оборваны -мы ее полностью контролируем и можемполностью проверить ее работуДля этого может понадобиться создатьеще несколько заглушек, которые будутвыдавать нужные данные для конкретныхтестов

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-164

Проблемы покрытия legacy-кодаВ итоге получается, что надо написатьдостаточно много дополнительного кодатолько для того, чтобы написать первыйтестОднако для второго теста, такого кодапотребуется уже меньше«Десятый» тест уже пишется спокойно, сиспользованием ранее написанного кода

НаследованныйНаследованный кодкод иимодульныемодульные тестытесты

2-165

Учебный Центр Luxoft www.luxoft.ru/edu

55

Page 56: Tdd Workbook

ПланПлан курсакурсаМодуль 1: Модульные тесты

2-166

Тестирование как способ обеспечениякачества продуктаУровни тестированияЦели и задачи модульного тестированияПокрытие кодаУнаследованный кодОрганизационные аспектытестирования

Слишком простой кодКак правило, так кажется только в моментего написанияЧерез полгода (а может и через парунедель) связи этого кода с другими могутпоказаться не такими очевидными, а самкод – не таким уж и простым

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-167

Тесты сложнее, чем сам кодКак правило, такая ситуация возникает вдвух случаях:низкая квалификация разработчикаплохой дизайн тестируемого кода

Возникают ситуации, когда протестироватькласс практически невозможно – напр. необходимо зарегистрироватьпользователя, добавить данные в БД, предоставить config-файлы и т.д.

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-168

Учебный Центр Luxoft www.luxoft.ru/edu

56

Page 57: Tdd Workbook

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

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-169

Тесты сложнее, чем сам кодКаждый класс, как и его тест, должны бытьнебольшими и понятнымиПосле того, как будет покрыт простейшийфункционал, можно перемещаться наболее «высокие» уровни системыОдновременно с этим производитьрефакторинг кода для уменьшениясвязности классов

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-170

Недостаточно времениЕсли сравнивать написание классов стестами и без, то безусловно, во второмварианте времени понадобится большеОднако давайте посмотрим на процессразработки и написания тестов болеешироко

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-171

Учебный Центр Luxoft www.luxoft.ru/edu

57

Page 58: Tdd Workbook

Недостаточно времениПри наличии модульных тестов, пишетсятолько тот код, который необходим для ихуспешного выполненияКлассы становятся меньше по размеру ивыполняют четко определенный наборфункцийТаким образом, пишется меньше кода

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-172

Недостаточно времениРазрабатывая небольшими шагами, вывсегда знаете, что вас ждет дальше – выдвигаетесь без промедленияИспользование unit-тестов существенносокращает время, проводимое вотладчикедобавив небольшую порцию кода, мы тутже убеждаемся в его работоспособности

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-173

Недостаточно временивнеся изменения в классы, мы тут жеубеждаемся, что не нарушили работыостальных классов

Интеграция модулей проходит легче ибыстрее, поскольку каждый из них хорошооттестированУменьшается количество ошибок в коде, а также время на их поиск и исправление

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-174

Учебный Центр Luxoft www.luxoft.ru/edu

58

Page 59: Tdd Workbook

Недостаточно времениБолее качественный дизайн полученный входе такой разработки, помогает вдальнейшем улучшать код, делая этоочень быстро

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-175

Не умеют писать тестыВ этом нет ничего страшного, т.к. необязательно сразу начинать тестироватьсложные компоненты, используя всевозможности xUnit и mock-фреймворковДля начала можно попытатьсявоспроизвести в тестах действия, которыеразработчик делает вручную притестировании модуля

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-176

Не умеют писать тестыДаже небольшая и «неуклюжая» тестоваяобвязка намного лучше, чем еще ненаписанная «гибкая система модульноготестирования, покрывающая 100% функционала»Начинайте с простых приемочных тестовили тестирования классов низших уровнейи продвигайтесь далее в глубь системы

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-177

Учебный Центр Luxoft www.luxoft.ru/edu

59

Page 60: Tdd Workbook

Двукратное увеличение кодаПо мнению некоторых разработчиков, модульные тесты – это двукратноеувеличение кодаЭто не такНа самом деле оно троекратное (илидаже больше)Однако давайте рассмотрим и другиестороны этого вопроса

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-178

Двукратное увеличение кодаВо-первых, тесты – это код, которыйдосконально проверяетработоспособность вашего кодВо-вторых, объем рабочего кодауменьшаетсяОднако, при изменении кода, необходимоизменять и тестирующий код, а этодвойная или тройная работа

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-179

Двукратное увеличение кодаКлассы становятсяузкоспециализированными с четкоопределенными интерфейсамиОни берут на себя как можно меньшеобязанностей, но выполняют их хорошоСнижаются зависимости между классамиБлагодаря этому изменения, вносимые всистему, носят локальный характер

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-180

Учебный Центр Luxoft www.luxoft.ru/edu

60

Page 61: Tdd Workbook

Двукратное увеличение кодаКонечно, можно спроектировать системутак, чтобы изначально обязанностиклассов были распределены оптимальнымобразомОднако на практике это практическиневозможно:никто не может увидеть всей картиныцеликомтребования к системе могут меняться

ПочемуПочему разработчикиразработчики ненехотятхотят внедрятьвнедрять uu--тестытесты

2-181

ПланПлан курсакурсаМодуль 1: Модульное тестирование

2-182

Тестирование как способ обеспечениякачества продуктаУровни тестированияЦели и задачи модульного тестированияПокрытие кодаУнаследованный кодОрганизационные аспекты тестирования

Вопросы и ответы

Учебный Центр Luxoft www.luxoft.ru/edu

61

Page 62: Tdd Workbook

ПрактикумПрактикумУпражнение 1

2-184

Разработка приложения по Use-case диаграммеПроработка методологии модульноготестированияРазработка собственных модульных тестов

МодульМодуль 22

Рассматриваемые темы:ВведениеОсновные этапы разработкимодульных тестовПростые тестыЗапуск тестированияНаборы тестов

Каркас JUnit

2-185

КаркасКаркас JUnitJUnit

JUnit – open-source продуктJUnit – часть семейства каркасовмодульного тестирования xUnit дляразличных платформпрограммированияВ разработке JUnit участвовал К. Бек, идеолог eXtreme ProgrammingРаспространяется одним jar-файломjunit.jar

2-186

JUnit

Учебный Центр Luxoft www.luxoft.ru/edu

62

Page 63: Tdd Workbook

КаркасКаркас JUnitJUnit

Специфика библиотеки –разработчик используетбиблиотекуСпецифика каркаса – каркасиспользует классы разработчика

2-187

JUnit как каркас

КаркасКаркас JUnitJUnit

Сравнение (assertion) ожидаемых иреальных результатов выполнениямодуляФикстуры – разделяемые междутестами данные и бизнес-логикаНаборы тестов для улучшеннойорганизации тестированияТекстовая и графическая средазапуска тестов

2-188

Основные положения JUnit

КаркасКаркас JUnitJUnit

Разработчик может тестировать:> Непосредственно модули или их наборы> Реализовать сложную бизнес-логикутестирования

2-189

Основные положения JUnit

Учебный Центр Luxoft www.luxoft.ru/edu

63

Page 64: Tdd Workbook

ОсновныеОсновные классыклассы каркасакаркаса

Пакет junit.framework

2-190

КлючевыеКлючевые классыклассы

Разработчик наследуется откласса TestCase для созданиясвоего тестаКласс TestCase реализует шаблонразработки TemplateЭто значит, что в нем реализованкаркас бизнес-логики, ссылающийся на методы, определенные в потомках 2-191

Класс TestCase

КлючевыеКлючевые классыклассы

2-192

Класс TestCase

Определяет каркасбизнес-логикиСсылается наабстрактные методы, определяемые впотомках:> setUp()> Тестовые методы> tearDown()

public void run(){setUp();runTest();tearDown();

}

Учебный Центр Luxoft www.luxoft.ru/edu

64

Page 65: Tdd Workbook

КлючевыеКлючевые классыклассы

Разработчик использует классTestSiute для формированиянабора тестовНаборы тестов могут включать всебя одиночные тесты и другиенаборы тестовРеализует шаблон разработкиComposite

2-193

Класс TestSuite

КлючевыеКлючевые классыклассы

2-194

Класс TestSuite

КлючевыеКлючевые классыклассы

Отношения ключевых классов

2-195

Учебный Центр Luxoft www.luxoft.ru/edu

65

Page 66: Tdd Workbook

КаркасКаркас JUnitJUnit

Рассматриваемые темы:ВведениеОсновные этапы разработкимодульных тестовПростые тестыЗапуск тестированияНаборы тестов

2-196

КаркасКаркас JUnitJUnit

Создать свой класс теста – наследник отTestCaseВ нем определить методы тестированиявида testXXX()Создать фикстуры – наборы данных илогики, используемых при каждом тестеВозможно, объединить несколько тестов внаборЗапустить тест (текстовой/графическийинтерфейс или в среде разработки)

2-197

Основные этапы разработки теста

КаркасКаркас JUnitJUnit

2-198

Неполный пример тестаimport java.util.*;import junit.framework.*;

public class SimpleTest extends TestCase {

public void testEmptyCollection() {Collection testCollection = new ArrayList();assertTrue( testCollection.isEmpty());

}

public static void main( String args[] ){junit.textui.TestRunner.run(SimpleTest.class);

}}

SimpleTest.java

11

22

334455

6677

Учебный Центр Luxoft www.luxoft.ru/edu

66

Page 67: Tdd Workbook

КаркасКаркас JUnitJUnit

Рассматриваемые темы:ВведениеОсновные этапы разработкимодульных тестовПростые тестыЗапуск тестированияНаборы тестов

2-199

КаркасКаркас JUnitJUnit

2-200

Тестируемый класс

public class IntCalculator {

int plus( int a, int b ) {return a + b;

}

int minus( int a, int b ) {return a - b;

}

}IntCalculator.java

КаркасКаркас JUnitJUnit

2-201

Тестируемый класс

Сколько модулей мы имеем длятестирования?

Учебный Центр Luxoft www.luxoft.ru/edu

67

Page 68: Tdd Workbook

КаркасКаркас JUnitJUnit

Класс теста наследуется от классаTestCaseКласс теста имеет методытестирования вида testXXX()Название методов произвольно, важен префикс test

2-202

Класс теста

КаркасКаркас JUnitJUnit

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

2-203

Метод теста

КаркасКаркас JUnitJUnit

В методах тестированиянеобходимо сравниватьполученные результатывыполнения модуля сожидаемыми

2-204

Метод теста

Учебный Центр Luxoft www.luxoft.ru/edu

68

Page 69: Tdd Workbook

КаркасКаркас JUnitJUnit

Каркас предлагает специальныеметоды сравнения (assertion)Разработчику теста необходимотолько вызвать их, а результатысравнения будут переданы каркасуавтоматически

2-205

Сравнение

2-206

Методы сравнения

Сравнение на эквивалентность assertEquals

Сравнение на истинность assertTrue, assert

Сравнение на ложность assertFalse

Сравнение на null assertNullСравнение на не-null assertNotNull

Сравнение на идентичность assertSame

Сравнение на не-идентичность assertNotSame

КаркасКаркас JUnitJUnit

2-207

Методы сравнения

КаркасКаркас JUnitJUnit

Учебный Центр Luxoft www.luxoft.ru/edu

69

Page 70: Tdd Workbook

2-208

Методы сравнения

КаркасКаркас JUnitJUnit

2-209

Методы сравнения

Эти методы сравненияперегружены для всехпримитивных типов Java и классаObject

КаркасКаркас JUnitJUnit

2-210

Пример метода тестирования

КаркасКаркас JUnitJUnit

import junit.framework.*;

public class IntCalculatorTest extends TestCase {public IntCalculatorTest(String s){

super(s);}public void testAdd() {

IntCalculator calc = new IntCalculator();assertEquals( calc.plus(2,2), 4 );

}

public static void main( String args[] ){junit.textui.TestRunner.run(IntCalculatorTest.class);

}}

IntCalculatorTest.java

11

2233

445566

7788

Учебный Центр Luxoft www.luxoft.ru/edu

70

Page 71: Tdd Workbook

КаркасКаркас JUnitJUnit

Failure – это ошибки сравнений> Выбрасываются assert-методами

Error – сбои, не связанные сосравнениями> Исключения, специфичные для бизнес-логики программы, а не тестирования

2-211

Ошибки (failures) и сбои (errors)

КаркасКаркас JUnitJUnit

Failures и Errors передаютсякаркасу, и он сигнализирует о нихтестировщику

2-212

Ошибки (failures) и сбои (errors)

2-213

Методы тестирования

В некоторых случаях необходимоявно сигнализировать каркасу оFailureДля этого предусмотреныспециальные методы

void fail()void fail( String s )

КаркасКаркас JUnitJUnit

Учебный Центр Luxoft www.luxoft.ru/edu

71

Page 72: Tdd Workbook

2-214

Фикстуры

КаркасКаркас JUnitJUnit

Фикстура – набор операций, выполняемых до и после тестовОни выполняются для каждоготеста testXXX

Каковы задачи фикстур?

2-215

Фикстуры

КаркасКаркас JUnitJUnit

Фикстуры реализуются методамиsetUp()tearDown()

КаркасКаркас JUnitJUnit

Рассматриваемые темы:Основные классыОсновные этапы разработкимодульных тестовПростые тестыЗапуск тестированияНаборы тестов

2-216

Учебный Центр Luxoft www.luxoft.ru/edu

72

Page 73: Tdd Workbook

КаркасКаркас JUnitJUnit

Тестирование можно запуститькак из самого класса теста, так ииз командной строкиДля повышения гибкости следуетиспользовать запуск изкомандной строки

2-217

Запуск тестирования

КаркасКаркас JUnitJUnit

Каркас предлагает два класса-launcher для запуска тестов:> Текстовой launcher

junit.textui.TestRunner> Графический launcher

junit.swingui.TestRunner

2-218

Запуск тестирования

КаркасКаркас JUnitJUnit

2-219

Пример запуска тестирования

Учебный Центр Luxoft www.luxoft.ru/edu

73

Page 74: Tdd Workbook

КаркасКаркас JUnitJUnit

2-220

Пример запуска тестирования

КаркасКаркас JUnitJUnit

2-221

Пример запуска тестирования

КаркасКаркас JUnitJUnit

2-222

Пример запуска тестирования

Учебный Центр Luxoft www.luxoft.ru/edu

74

Page 75: Tdd Workbook

КаркасКаркас JUnitJUnit

Рассматриваемые темы:Основные классыОсновные этапы разработкимодульных тестовПростые тестыЗапуск тестированияНаборы тестов

2-223

КаркасКаркас JUnitJUnit

Каркас предлагает возможностьобъединять тесты в наборыВ наборы можно включать какодиночные тесты, так и другиенаборы

2-224

Наборы тестов – Tests Suites

КаркасКаркас JUnitJUnit

Для создания собственногонабора тестов необходимонаследоваться от класса TestSuiteВ нем необходимо определитьстатический метод suite(), методформирования набора

2-225

Наборы тестов – Tests Suites

Учебный Центр Luxoft www.luxoft.ru/edu

75

Page 76: Tdd Workbook

2-226

Пример набора тестов

КаркасКаркас JUnitJUnit

import junit.framework.*;

public class AllCalculatorTests extends TestSuite {static public Test suite() {

TestSuite mySuite = new TestSuite();mySuite.addTestSuite( IntCalculatorTest.class );return mySuite;

}}

AllCalculatorTests.java

1122334455

Какие методы класса теста будут вызваны?

2-227

Запуск наборов тестов

КаркасКаркас JUnitJUnit

Набор тестов запускается так же, как и отдельный тест

2-228

Пример запуска наборов тестов

КаркасКаркас JUnitJUnit

Учебный Центр Luxoft www.luxoft.ru/edu

76

Page 77: Tdd Workbook

2-229

Пример запуска наборов тестов

КаркасКаркас JUnitJUnit

КаркасКаркас JUnitJUnit

Рассмотренные темы:Основные классыОсновные этапы разработкимодульных тестовПростые тестыЗапуск тестированияНаборы тестов

2-230

2-231

Упражнение 2

ПрактикумПрактикум

Разработка Junit-тестов ввыработанной методологии

Учебный Центр Luxoft www.luxoft.ru/edu

77

Page 78: Tdd Workbook

РефакторингРефакторинг

СодержаниеСодержание

ОсновныеОсновные понятияпонятияКодКод сс душкомдушкомКаталогКаталог рефакторинговрефакторинговИнструментыИнструментыЛитератураЛитература

ЧтоЧто этоэто??

РефакторингРефакторинг ((refactoring) (refactoring) (сущсущ.) .) –– изменениеизменениевово внутреннейвнутренней структуреструктуре программногопрограммногообеспеченияобеспечения, , имеющееимеющее цельюцелью облегчитьоблегчитьпониманиепонимание егоего работыработы ии упроститьупроститьмодификациюмодификацию, , безбез измененияизменения егоегоповеденияповедения..ПроводитьПроводить рефакторингрефакторинг ((refactorrefactor) () (глагглаг.) .) ––изменятьизменять структуруструктуру програмногопрограмногообеспеченияобеспечения, , нене затрагиваязатрагивая егоего поведенияповедения..

Учебный Центр Luxoft www.luxoft.ru/edu

78

Page 79: Tdd Workbook

ЗачемЗачем проводитьпроводить рефакторингрефакторинг??

УлучшаетУлучшает дизайндизайн программногопрограммного обеспеченияобеспеченияОблегчаетОблегчает пониманиепонимание программногопрограммного обеспеченияобеспеченияПозволяетПозволяет быстреебыстрее добавлятьдобавлять новыйновый функционалфункционалПомогаетПомогает находитьнаходить ошибкиошибкиПозволяетПозволяет писатьписать кодкод быстреебыстрее

ПочемуПочему рефакторингрефакторинг даетдает результатырезультаты??

ПишитеПишите кодкод длядля сегоднясегодня, , ноно думаетедумаете пропро завтразавтраТрудноТрудно модифицироватьмодифицировать> “нечитаемые” программы> программы с дублированием кода> программы со сложной логикой условныхоператоров

> работающий код, требующий новогофункционала

БезопасныйБезопасный путьпуть модификациимодификации программпрограмм вв легколегко--модифицируемыемодифицируемые

КогдаКогда проводитьпроводить рефакторингрефакторинг??

ПравилоПравило трехтрех> Когда вы делаете одно и то же в третий раз, начинайте рефакторинг

ПриПри добавлениидобавлении новойновой функциифункции> сделайте код более очевидным> как должен был бы быть спроектирован код, чтобы добавить функцию было легко

ПриПри исправленииисправлении ошибокошибок> потому что не смогли увидеть ошибкуПриПри разбореразборе кодакода

Учебный Центр Luxoft www.luxoft.ru/edu

79

Page 80: Tdd Workbook

КакКак мотивироватьмотивировать руководителяруководителя??

ХорошийХороший руководительруководитель ((техническитехнически--грамотныйграмотный))> ориентирован на качество> хороший способ внедрения – использование приразборе кода

РуководительРуководитель, , подгоняемыйподгоняемый графикомграфиком> не говорите ☺> ему все равно как вы укладываетесь в графикДолгиДолги проектированияпроектирования ((когдакогда мымы начнемначнем ихихоплачиватьоплачивать?)?)> не удаляется дублирование кода> ну упрощается код> не проясняется назначение кода

““КакКак долгодолго вывы нене выплачиваетевыплачиваете платежиплатежи попокредитамкредитам??””

ПроблемыПроблемы припри рефакторингерефакторинге

НеНе видновидно, , чточто приводитприводит кк ростуросту производительностипроизводительностиРефакторингРефакторинг базбаз данныхданных> трудно модифицировать структуру> миграция данных> поддержка нескольких версий БДРефакторингРефакторинг XMLXML> поддержка нескольких версий> необходимость модификации внешних клиентов> синхронизация протоколовИзмененияИзменения интерфейсовинтерфейсов> опубликованные SDK и APIИзмененияИзменения архитектурыархитектуры> Радикальные изменения трудно/невозможновоплотить, используя рефакторинг

КогдаКогда рефакторингрефакторинг делатьделать нене нужнонужно??

НеобходимостьНеобходимость переписатьпереписать всевсе сс нулянуля> когда не удается сделать код устойчивымБлизостьБлизость срокасрока завершениязавершения проектапроекта> преимущества появится после срока сдачи

Учебный Центр Luxoft www.luxoft.ru/edu

80

Page 81: Tdd Workbook

РефакторингРефакторинг ии юнитюнит--тестытесты

РефакторингРефакторинг требуеттребует юнитюнит--тестовтестов> даже автоматизированные рефакторинги могутбыть источником ошибок

ПреждеПрежде чемчем осуществлятьосуществлять рефакторингрефакторингфрагментафрагмента, , сделайтесделайте кодкод самотестирующимсясамотестирующимсяЗапускайтеЗапускайте тестытесты додо ии послепосле рефакторингарефакторинга

РефакторингРефакторинг ии проектированиепроектирование

НеНе являетсяявляется заменазамена предварительномупредварительномупроектированиюпроектированиюСмещаютсяСмещаются акцентыакценты> цель проектирования найти не единственноправильно решение, а приемлемое

СтремлениеСтремление кк простотепростоте> гибкие решение сложнее> лучше иметь возможность легко изменятьархитектуру

КодКод сс душкомдушком

МетафораМетафора длядля описанияописания местмест вв проектепроекте, , которымкоторымвозможновозможно требуетсятребуется переработкапереработкаВоспринимаетсяВоспринимается легчелегче, , чемчем ““эстетикаэстетикаархитектурыархитектуры””ЧтобыЧтобы определитьопределить ““когдакогда”” нуженнужен рефакторингрефакторингЧтобыЧтобы определитьопределить ““когдакогда”” остановитсяостановится

Учебный Центр Luxoft www.luxoft.ru/edu

81

Page 82: Tdd Workbook

ДублированиеДублирование

for (Node childNode = node.getFirstChild();childNode != null;){

String value=node.getTextContent();

if(value!=null && value.trim().length()>0)this.status=value;

Node nextChild = childNode.getNextSibling();...................

}........................ for (Node childNode = node.getFirstChild();childNode != null;){

String value=node.getTextContent();

if(value!=null && value.trim().length()>0)this.code=value;

Node nextChild = childNode.getNextSibling();...................

}

ДублированиеДублирование

СимптомыСимптомы> практически одинаковые фрагменты кода> фрагменты имеющие одинаковый эффект (налюбом концептуальном уровне)

КакКак исправитьисправить> выделение метода> шаблонный метод> замещение алгоритма> выделение класса

ДлинныйДлинный методметод

public getLDAPClasses(){

if (serverLDAPConf == null)throw new LDAPConnectionException("Server Ldap should not be null.");

ldapConnection = init(serverLDAPConf);// login/password local changing if anonymoususeActualCredentialsIfAnonymous(serverLDAPConf);ArrayList<String> attrNames = new ArrayList<String>();Attributes schemaAttrs;try{

// it uses getConnectionInfo(), stored in Connection object,// but sets the Username/Passsword to the new specified valuesisAuthenticated = ldapConnection.authenticateUI(user, password);if (!isAuthenticated)

throw new LDAPConnectionException("Not authenticated.");schemaAttrs = ldapConnection.doLDAPSchemaSearch(user, password, objectClass);Attribute mustList = schemaAttrs.get(LDAP_OBJECT_CLASS_MUST_FIELD);if (mustList != null){

addAttrNameToList(attrNames, mustList.getAll());}Attribute mayList = schemaAttrs.get(LDAP_OBJECT_CLASS_MAY_FIELD);if (mayList != null){

addAttrNameToList(attrNames, mayList.getAll());}Collections.sort(attrNames);

}catch (NamingException nameEx){

Logger.getLogger(this.getClass()).error(ResourceBundleUtils.getFormatingBundleProperty(AdminResourceBundle.adminLog,

"request-ldap-failed", nameEx.getMessage()));throw new LDAPConnectionException("Request for LDAP attribute name list failed. See logs.");

}return attrNames;

}

Учебный Центр Luxoft www.luxoft.ru/edu

82

Page 83: Tdd Workbook

ДлинныйДлинный методметод

СимптомыСимптомы> большое количество строк кода в методеКакКак исправитьисправить> выделение метода

БольшойБольшой класскласс

import javax.swing.event.DocumentListener;import static java.awt.BorderLayout.*;

................... 500+ imports ...........................

public class ClientFrame extends JFrame{

private static final String APP_TITLE = "URLyBird booking system";private static final int CUSTOMER_COLUMN = 6;

................... 30+ constants ...........................

private JPanel searchPanel;private JTextField hotelLocation = createTextField(20);private JTextField hotelName = createTextField(20);private DataSet dataSet = new DataSet(String.class, String.class, Long.class, Boolean.class, Rate.class, Date.class,

String.class);private DataTableModel model;private JTable resultTable;private SelectionGroup selectionGroup = new SelectionGroup();

................... 110+ members ...........................

public ClientFrame(String filename){

this();setUseLiveSearch(true);setData(openDB.getData(filename));

}

public ClientFrame(String host, int port){

this();setUseLiveSearch(false);setData(connect.getData(host, port));

}

................... 205+ methods ...........................}

БольшойБольшой класскласс

СимптомыСимптомы> большое количество членов класса> большое количество методов класса> большое количество строк кода классеКакКак исправитьисправить> выделение класса> выделение подкласса> выделение интерфейса

Учебный Центр Luxoft www.luxoft.ru/edu

83

Page 84: Tdd Workbook

ДлинныйДлинный списоксписок параметровпараметров

/*** Authenticates agains LDAP v.3 directory*/

public boolean authenticate (String hostname, String protocol, int port, String username,String password, Certificate x509, boolean useSsl, boolean bindAnonymously)

{..........................................}

ДлинныйДлинный списоксписок параметровпараметров

СимптомыСимптомы> метод имеет больше 2-4 параметровКакКак исправитьисправить> замена параметра вызовом метода> сохранить целиковый объект> ввести объект-параметр

ГипотетическаяГипотетическая всеобщностьвсеобщность

СимптомыСимптомы> общие решения для будущего> реально не используются (“про запас)”> слишком сложное решение для текущей задачиКакКак исправитьисправить> Сворачивание иерархии> Встраивание класса> Переименование метода

Учебный Центр Luxoft www.luxoft.ru/edu

84

Page 85: Tdd Workbook

ЦепочкиЦепочки сообщенийсообщений

СимптомыСимптомы> Вызовы типа:

a.b().c().d();КакКак исправитьисправить> выделение метода> перемещение метода> сокрытие делегата

КомментарииКомментарии

// creating cert path// and getting the first issuerList<X509Certificate> certPathList = new ArrayList<X509Certificate>();certPathList.add(peerCertificate);……………………………………………….if (firstIssuer == null){

// we dont't trust the peer cert at all……………………………….

}if (!firstIssuer.equals(peerCertificate)){

// need to search in the trusted CA for the rest of the cert pathX509Certificate curCert = firstIssuer;

……………………………………}//remove most-trusted CA from pathif (certPathList.size() > 0)

certPathList.remove(certPathList.size() - 1);

КомментарииКомментарии

СимптомыСимптомы> большое количество комментариев в коде> “что”, а не “почему”КакКак исправитьисправить> выделение метода> переименование метода> введение утверждения

Учебный Центр Luxoft www.luxoft.ru/edu

85

Page 86: Tdd Workbook

АльтернативныеАльтернативные классыклассы сс разнымиразнымиинтерфейсамиинтерфейсами

class DateUtils{

Date nowUtc(int offset){

.................}

}

class Utils{

Date now(){

...................}

}

АльтернативныеАльтернативные классыклассы сс разнымиразнымиинтерфейсамиинтерфейсами

СимптомыСимптомы> Существует 2 и более реализации одного итого же, но с разным интерфейсом

КакКак исправитьисправить> переименование метода> перемещение метода> выделение родительского класса

ВременноеВременное полеполе

public class Balance{

private int noOfPeopleInDepartment;private int noOfPeopleInOfshore;

public calculateBalance(Department dep){

noOfPeopleInDepartment=dep.getHeadCount();..................

}}

Учебный Центр Luxoft www.luxoft.ru/edu

86

Page 87: Tdd Workbook

ВременноеВременное полеполе

СимптомыСимптомы> значение поля устанавливается только вопределенных условиях

КакКак исправитьисправить> выделение класса

ЛенивыйЛенивый класскласс

class Male extends Human{

String getType(){

return "M";}

}

ЛенивыйЛенивый класскласс

СимптомыСимптомы> класс не выполняет никакой работыКакКак исправитьисправить> свертывание иерархии> встраивание класса

Учебный Центр Luxoft www.luxoft.ru/edu

87

Page 88: Tdd Workbook

ОператорыОператоры switchswitch

switch(period){

case: SUMMER_PERIOD{

rate=rate*0.7-monthDiscount; }case: HOLIDAY_PERIOD{

rate=rate*0.6;}case: NORMAL_PERIOD{

rate=rate-monthDiscount;}

}

ОператорыОператоры switchswitch

СимптомыСимптомы> switch выражения> много идущих подряд if, else-if > instanceofКакКак исправитьисправить> не эмулируйте наследование> выделение метода> перемещение метода, замена кода типаподклассом или стратегией/состоянием

> замена условных выражений полиморфизмом> замена параметра явными методами> введение null-объекта

ГруппыГруппы данныхданных

public class Scheduler{

private Date startOfWorkPeriod;private Date endOfWorkPeriod;private Date rateOfWorkPeriod;

private Date startOfSupportPeriod;private Date endOfSupportPeriod;private Date rateOfSupportPeriod;

………………………………

}

Учебный Центр Luxoft www.luxoft.ru/edu

88

Page 89: Tdd Workbook

ГруппыГруппы данныхданных

СимптомыСимптомы> одни и те же параметры часто встречаютсявместе как поля классов или аргументыметодов

> группы названий полей содержат одинаковыеподстроки

КакКак исправитьисправить> выделение класса> введение объекта-параметра> сохранение целого объекта> перемещение метода

ОдержимостьОдержимость элементарнымиэлементарными типамитипами

final int static MONDAY=1;final int static TUESDAY=2;final int static WEDNESDAY=2;

//calculate price in USDdouble price=hourRate*hours;double priceInUSD=price*USD_TO_RUR_RATE;

ОдержимостьОдержимость элементарнымиэлементарными типамитипами

СимптомыСимптомы> использование примитивных типов для работысо структурными данными

> перечисления и константы представляются спомощью int

> строковые название представляют названияполей

КакКак исправитьисправить> замена значения данных объектом> замена кода типа классом> замена кода типа подклассами> замена кода типа состоянием/стратегией> выделение классов> введение объекта-параметра> замена массива объектом

Учебный Центр Luxoft www.luxoft.ru/edu

89

Page 90: Tdd Workbook

КлассыКлассы данныхданных

public class DataClass{

private Date start;private Date end;private double rate;

public Date getStart() { return start; }

public void setStart(Date start) { this.start = start; }

public Date getEnd() { return end; }

public void setEnd(Date end) { this.end = end; }

public double getRate() { return rate; }

public void setRate(double rate) { this.rate = rate; }}

КлассыКлассы данныхданных

СимптомыСимптомы> содержат только данные и методы для ихполучения и установки

> нет поведенияКакКак исправитьисправить> инкапсуляция поля> инкапсуляция коллекции> удаление метода установки значения> перемещение метода> сокрытие метода

ПосредникПосредник

public class Director{

Calendar scheduler;

public void scheduleMeeting(Date start){

scheduler.scheduleMeeting(start);}

public void scheduleCall(Date start){

scheduler.scheduleCall(start);}

………………………………………….}

Учебный Центр Luxoft www.luxoft.ru/edu

90

Page 91: Tdd Workbook

ПосредникПосредник

СимптомыСимптомы> класс делегирует выполнение более половиныметодов

КакКак исправитьисправить> удаление посредника> замена делегирования наследованием

ОтказОтказ отот наследстванаследства

СимптомыСимптомы> подкласс не использует данные или методародителя

> использование данных или методов родителясвязано с проблемами

КакКак исправитьисправить> замена наследование делегированием> выделение подкласса> спуск поля> спуск метода

ЗавистливыеЗавистливые функциифункции

class Processor{

private Queue executionQueue;

public void scheduleExecutionOrder(){

int pos=executionQueue.getCurrentPosition();

if(pos=executionQueue.length())executionQueue.increaseBuffer(POOL_STEP);

executionQueue.add(task);}

}

Учебный Центр Luxoft www.luxoft.ru/edu

91

Page 92: Tdd Workbook

ЗавистливыеЗавистливые функциифункции

СимптомыСимптомы> метод манипулирует больше данными другогокласса, чем того где объявлен

КакКак исправитьисправить> перемещение метода> выделение метода

РасходящиесяРасходящиеся модификациимодификации

СимптомыСимптомы> часто приходится модифицировать класс посовершенно разным причинам

КакКак исправитьисправить> выделение класса> выделение подкласса> выделение суперкласса

СтрельбаСтрельба дробьюдробью

СимптомыСимптомы> для внесения каждого изменения необходимопоменять несколько классов

КакКак исправитьисправить> встраивание класса> перемещение метода> перемещение поля

Учебный Центр Luxoft www.luxoft.ru/edu

92

Page 93: Tdd Workbook

РефакторингиРефакторинги

КомпозицияКомпозиция методовметодовПерераспределениеПерераспределение функцийфункций междумежду объектамиобъектамиОрганизацияОрганизация данныхданныхРаботаРабота сс условнойусловной логикойлогикойУпрощениеУпрощение вызововвызововОбобщениеОбобщение

КомпозиционныеКомпозиционные

ВыделениеВыделение методаметодаВстраиваниеВстраивание методаметодаВстраиваниеВстраивание временнойвременной переменнойпеременнойЗаменаЗамена временнойвременной переменнойпеременной вызовомвызовомВведениеВведение поясняющейпоясняющей переменнойпеременнойРазбиениеРазбиение временнойвременной переменнойпеременнойУдалениеУдаление присваиванийприсваиваний параметрампараметрамЗаменаЗамена методаметода объектомобъектом методовметодовЗамещениеЗамещение алгоритмаалгоритма

ВыделениеВыделение методаметода ((extract method)extract method)

for (…..){String value=node.getTextContent();

if(value!=null && value.trim().length()>0)this.status=value;

…………….....................}

for (…..){

String value=node.getTextContent();

if(!isEmpty(value))this.status=value;

...................}

public boolean isEmpty(String str){

return value!=null && value.trim().length()>0;}

Когда: есть фрагмент кода, который можно сгруппировать

Учебный Центр Luxoft www.luxoft.ru/edu

93

Page 94: Tdd Workbook

ВстраиваниеВстраивание методаметода ((inline method)inline method)

public int getStatus(){

return (lengthMoreThanLimit(record)) ? 2 : 1;}

private void lengthMoreThanLimit(String record){

return record.length() > 10;}

public int getStatus(){

return (record.length()>10) ? 2 : 1;}

Когда: тело метода также очевидно как его название

ВстраиваниеВстраивание временнойвременной переменнойпеременной (inline (inline temp)temp)

public void calculateResult() {

int result = calculator.power(x, y);return result;

}

public void calculateResult(){

return calculator.power(x, y);}

Когда: есть временная переменная, которой присваиваетсязначение один раз, переменная мешает дальнейшимрефакторингам

ЗаменаЗамена временнойвременной переменнойпеременной вызовомвызовом(Replace Temp with Query)(Replace Temp with Query)

public void balance(){

double basePrice = quantity * itemPrice;

if (basePrice > 1000)return basePrice * 0.95;

elsereturn basePrice * 0.98;

}

public void balance(){

if (basePrice() > 1000)return basePrice() * 0.95;

elsereturn basePrice() * 0.98;

}

private double basePrice(){

return quantity * itemPrice;}

Когда: временная переменная используются для хранениязначения выражения

Учебный Центр Luxoft www.luxoft.ru/edu

94

Page 95: Tdd Workbook

ВведениеВведение поясняющейпоясняющей переменнойпеременной((introducing explaining variable)introducing explaining variable)

if(platform.toUpperCase().indexOf("MAC")>-1 &&

browser.toUpperCase().indexOf("IE")>-1 &&

wasInitizalized() && resize>0){

......................}

boolean isMac = platform.toUpperCase().indexOf("MAC") > -1;

double isIE = browser.toUpperCase().indexOf("IE");

boolean canResize = resize > 0;

if(isMac && isIE >-1 && wasInitizalized() && canResize){

......................}

Когда: есть сложное выражение

РазбиениеРазбиение временнойвременной переменнойпеременной ((split split temporary variable)temporary variable)

public void printInfo() {

double res = 2 * (height + width);System.out.println(res);

res = height * width;System.out.println(res);

}

public void printInfo() {

double perimeter = 2 * (height + width);System.out.println(perimeter);

double area = height * width;System.out.println(area);

}

Когда: есть временная переменная, которой много разприсваиваются значения, но не переменная цикла и ненакопление результата

УдалениеУдаление присваиванийприсваиваний параметрампараметрам ((remove remove assignments to parameters)assignments to parameters)

public void doIt(int input,int quantity) {

if(quantity>1000)input=input-2;

}

public void doIt(int input,int quantity){

int result=input;

if(quantity>1000)result=result-2;

}

Когда: код выполняет присваивание параметру

Учебный Центр Luxoft www.luxoft.ru/edu

95

Page 96: Tdd Workbook

ЗаменаЗамена методаметода объектомобъектом методовметодов ((replace replace method with method object)method with method object) (1)(1)

class Order{

public int price(int input){

double primaryBasePrice;double secondaryBasePrice;double tertiaryBasePrice;

int importantValue=primaryBasePrice*quantity*input;int importantValue2=secondaryBasePrice+quantity*input;if(input>1000)

importantValue=importantValue-tertiaryBasePrice*input;

int importantValue3=importantValue2+tertiaryBasePrice*quantity;.........................

}}

Когда: есть длинный метод, в котором локальные переменныене позволяют применить “выделение метода”

ЗаменаЗамена методаметода объектомобъектом методовметодов ((replace replace method with method object) (2)method with method object) (2)

class Order{

public int price(int input){

returnnew PriceCalculator(this,

input,primaryBasePrice,secondaryBasePrice,tertiaryBasePrice).compute();

}}

class PriceCalculator{

Order source;int value;

double primaryBasePrice;double secondaryBasePrice;double tertiaryBasePrice;

int importantValue;int importantValue2;int importantValue3;

int compute(){

.....................}

}

ЗамещениеЗамещение алгоритмаалгоритма ((substitute algorithm)substitute algorithm)

public String find(String[] people){

for(int i=0;i<people.length;i++){

if(people[i].equals("Don"))return "Don";

if(people[i].equals("John"))return "John";

if(people[i].equals("Mark"))return "Mark";

}

return "";}

public String find(String[] people){

List candidates = Arrays.asList({"Don", "John", "Ken"});

for (int i = 0; i < people.length; i++)if(candidates.contains(people[i]))

return people[i];

return "";}

Когда: найден более понятный способ решения

Учебный Центр Luxoft www.luxoft.ru/edu

96

Page 97: Tdd Workbook

ПерераспределениеПерераспределение функцийфункций междумеждуобъектамиобъектами

ПеремещениеПеремещение методаметодаПеремещениеПеремещение поляполяВыделениеВыделение классаклассаВстраиваниеВстраивание классаклассаСокрытиеСокрытие делегированияделегированияУдалениеУдаление посредникапосредникаВведениеВведение внешнеговнешнего методаметодаВведениеВведение локальноголокального расширениярасширения

ПеремещениеПеремещение методаметода ((move method)move method)

Когда: метод чаще использует функции другого класса, а нетого где определен

ПеремещениеПеремещение поляполя (move field)(move field)

Когда: поле используется другим классом чаще, чем тем вкотором определено

Учебный Центр Luxoft www.luxoft.ru/edu

97

Page 98: Tdd Workbook

ВыделениеВыделение классакласса (extract class)(extract class)

Когда: класс выполняет работу, которую следует разделить надва класса

ВстраиваниеВстраивание классакласса ((inline class)inline class)

Когда: класс выполняет слишком мало функций

СокрытиеСокрытие делегированияделегирования((hide delegate)hide delegate)

Когда: клиент обращается к делегируемому классу объекта.

person.getDepartment().getManager()

Учебный Центр Luxoft www.luxoft.ru/edu

98

Page 99: Tdd Workbook

УдалениеУдаление посредникапосредника (remove middle man)(remove middle man)

Client Class

+getManager()

Department

+getManager()

Person

Когда: клиент слишком занят простым делегированием

ВведениеВведение внешнеговнешнего методаметода ((introduce foreign introduce foreign method)method)

Когда: необходимо ввести в класс дополнительный метод, ноотсутвует возможность модификации класса

Date next=new Date(previous.getYear(),previous.getMonth(),previous.getDate()+1);

Date next=nextDay(previous);

private static Date nextDay(Date now){

return new new Date(now.getYear(),now.getMonth(),now.getDate()+1);

}

ВведениеВведение локальноголокального расширениярасширения ((introduce introduce local extension)local extension)

+nextDay(in Date)+nextMonth(in Date)+nextYear(in Date)

Client Class

Когда: необходимо ввести в класс несколько дополнительныхметодов, но отсутвует возможность модификации класса

Учебный Центр Luxoft www.luxoft.ru/edu

99

Page 100: Tdd Workbook

ОрганизацияОрганизация данныхданных

СамоинкапсуляцияСамоинкапсуляция поляполяЗаменаЗамена значениязначения данныхданных объектомобъектомЗаменаЗамена значениязначения ссылкойссылкойЗаменаЗамена ссылкиссылки значениемзначениемЗаменаЗамена массивамассива объектомобъектомДублированиеДублирование видимыхвидимых данныхданныхЗаменаЗамена однонаправленнойоднонаправленной связисвязи двунаправленнойдвунаправленнойЗаменаЗамена двунаправленнойдвунаправленной связисвязи однонаправленнойоднонаправленнойЗаменаЗамена волшебноговолшебного числачисла константойконстантойИнкапсуляцияИнкапсуляция поляполяИнкапсуляцияИнкапсуляция коллекцииколлекцииЗаменаЗамена записизаписи классомклассом данныхданныхЗаменаЗамена кодакода типатипа классомклассомЗаменаЗамена кодакода типатипа подклассамиподклассамиЗаменаЗамена кодакода типатипа стратегиямистратегиями//состояниемсостояниемЗаменаЗамена подклассаподкласса полямиполями

СамоинкапсуляцияСамоинкапсуляция поляполя ((self encapsulated self encapsulated field)field)

Когда: обращение к полю происходит непосредственно

private int low,high;

public boolean includes(int value) {

return value>=low && value<=high; }

private int low,high;

public boolean includes(int value){

return value>=getLow() && value<=getHigh();}

public int getLow() {return low;}public int getHigh() {return high;}

ЗаменаЗамена значениязначения данныхданных объектомобъектом (replace (replace data value with object)data value with object)

Когда: есть элемент данных, для которого требуетсядополнительные данные или поведение

Учебный Центр Luxoft www.luxoft.ru/edu

100

Page 101: Tdd Workbook

ЗаменаЗамена значениязначения ссылкойссылкой ((change value to change value to reference)reference)

Когда: есть много одинаковых экземляров класса, которыетребуется заменить одним объектом

ЗаменаЗамена ссылкиссылки значениемзначением (change reference to (change reference to value)value)

Когда: есть маленький неизменяемый и неудобный вуправлении объект ссылки

ЗаменаЗамена массивамассива объектовобъектов((replace array with object)replace array with object)

Когда: есть массив, элементы которого представляют собойразные сущности

String data[] = new String[3];data[0] = "Liverpool";data[1]="15";

Perfomance perf=new Perfomance();perf.setName("Liverpool");perf.setWins(15);

Учебный Центр Luxoft www.luxoft.ru/edu

101

Page 102: Tdd Workbook

ДублированиеДублирование видимыхвидимых данныхданных ((duplicate duplicate observed dataobserved data))

Когда: есть данные предметной области приложения, которыесуществуют только в GUI классах, но к ним нужен доступметодам предметной области приложения

ЗаменаЗамена однонаправленнойоднонаправленной связисвязи двунаправленнойдвунаправленной (change (change unidirectional association to bidirectional)unidirectional association to bidirectional)

Когда:есть два класса, которые должны пользоватьсяметодами друг друга, но ссылка между ними есть только водном направлении

ЗаменаЗамена двунаправленнойдвунаправленной связисвязи однонаправленнойоднонаправленной ((change change bidirectional association to unidirectional)bidirectional association to unidirectional)

Когда: имеет двунаправленная связть, но одному из классовбольше не нужны методы второго

Учебный Центр Luxoft www.luxoft.ru/edu

102

Page 103: Tdd Workbook

ЗаменаЗамена волшебноговолшебного числачисла константойконстантой ((replace magic number replace magic number with symbolic constant)with symbolic constant)

Когда: есть массив, элементы которого представляют собойразные сущности

public double potentialEnergy(double mass,doubleheight)

{return mass * 9.81 * height;

}

static final double GRAVITATION_CONSTANT=9.81;

public double potentialEnergy(double mass,double height){

return mass * GRAVITATION_CONSTANT * height;}

ИнкапсуляцияИнкапсуляция поляполя(encapsulate field)(encapsulate field)

Когда: есть открытое поле

public int low,high;

public boolean includes(int value){

return value>=low && value<=high;

}

private int low,high;

public boolean includes(int value){

return value>=getLow() && value<=getHigh();}

public int getLow() {return low;}public int getHigh() {return high;}

ИнкапсуляцияИнкапсуляция коллекцииколлекции(encapsulate collection)(encapsulate collection)

Когда: метод возвращает коллекцию

Учебный Центр Luxoft www.luxoft.ru/edu

103

Page 104: Tdd Workbook

ЗаменаЗамена записизаписи классомклассом данныхданных ((replace record replace record with data class)with data class)

Когда: требуется взаимодействие со структурой втрадиционном стиле

struct DataRecord{

int id;String name;

}

class DataRecord{

private int id;private String name;

public DateRecord(int id, String name){

this.id = id;this.name = name;

}

public int getId() { return id; }public void setId(int id) { this.id = id; }

public String getName() { return name;}public void setName(String name) { this.name = name; }

}

ЗаменаЗамена кодакода типатипа классомклассом (replace type code (replace type code with class)with class)

Когда: у класса есть числовой тип, который не влияет на егоповедение

Person

-O : BloodGroup-A : BloodGroup-B : BloodGroup-AB : BloodGroup

BloodGroup

1

ЗаменаЗамена кодакода типатипа подклассамиподклассами (replace type (replace type code with subclasses)code with subclasses)

Когда: имеется неизменяемый код типа, который влияет наповедение класса

Employee

Engineer Salesman

Учебный Центр Luxoft www.luxoft.ru/edu

104

Page 105: Tdd Workbook

ЗаменаЗамена кодакода типатипа стратегиямистратегиями//состояниемсостоянием ((replace type code replace type code with state/strategywith state/strategy))

Когда: имеется неизменяемый код типа, который влияет наповедение класса, но нельзя применить создание подклассов

ЗаменаЗамена подклассаподкласса полямиполями ((replace subclass replace subclass with fieldswith fields))

Когда: есть подклассы, которые различаются толькометодами, возвращающими данные-константы

РаботаРабота сс условнойусловной логикойлогикой

ДекомпозицияДекомпозиция условногоусловного оператораоператораКонсолидацияКонсолидация условногоусловного выражениявыраженияКонсолидацияКонсолидация дублирующихсядублирующихся условныхусловныхфрагментовфрагментовУдалениеУдаление управляющегоуправляющего флагафлагаЗаменаЗамена вложенныхвложенных условныхусловных операторовоператоровграничнымграничным операторомоператоромЗаменаЗамена условногоусловного оператораоператора полиморфизмомполиморфизмомВведениеВведение nullnull--объектаобъектаВведениеВведение утвержденияутверждения

Учебный Центр Luxoft www.luxoft.ru/edu

105

Page 106: Tdd Workbook

ДекомпозицияДекомпозиция условногоусловного оператораоператора((decompose conditional)decompose conditional)

Когда: имеет сложная цепочка условных проверок (if-then-else)

if(date.before(SUMMER_START) ||date.after(SUMMER_END))charge=quantity*winterRate+winterServiceCharge;

elsecharge=quantity*summerRate;

if(notSummer(date))charge=winterCharge(quantity);

elsecharge=summerCharge(quantity);

КонсолидацияКонсолидация условногоусловного выражениявыражения(consolidate conditional expression)(consolidate conditional expression)

Когда: есть ряд проверок, дяющих одинаковый результат

public double accountStatus() {

if(seniority<2) return 0;if(monthDisabled>12) return 0;if(isPartTime) return 0;......................................

}

public double accountStatus(){

if(isNotEligable()) return 0;}

КонсолидацияКонсолидация дублирующихсядублирующихся условныхусловных фрагментовфрагментов((consolidate duplicate conditional fragmentsconsolidate duplicate conditional fragments))

Когда: один и тот же фрагмент кода присутствует во всехветвях условного выражения

if (isDiscountDeal()){

total = price * 0.94;send();

}else{

total = price * 0.98;send();

}

double total;

if (isDiscountDeal())total = price * 0.94;

elsetotal = price * 0.98;

send();

Учебный Центр Luxoft www.luxoft.ru/edu

106

Page 107: Tdd Workbook

УдалениеУдаление управляющегоуправляющего флагафлага ((remove remove control flagcontrol flag))

Когда: используется переменная, действующая какуправляющий флаг для ряда булевых выражений

boolean done=false;

while(!done){

if(rateLimitExceeded()){

....done=true;

}

if(isOverdrawn()){

.....done=true;

}else {........}

}

while(true){

if(rateLimitExceeded()){

....break;

}

if(isOverdrawn()){

.....break;

}else {.....}

}

ЗаменаЗамена вложенныхвложенных условныхусловных операторовоператоров граничнымграничнымоператоромоператором ((replace nested conditionals with guard clausesreplace nested conditionals with guard clauses))

Когда: есть условное поведение, из которого неясеннормальный путь выполнения

double getPayAmount(){

double result;

if(isDead) result=deadAmount();else{

if(isSeparated) result=separatedAmount();else{

if(isRetired) result=retiredAmount();else result=normalAmount();

}}return result;

}

double getPayAmount(){

if(isDead) return deadAmount();if(isSeparated) return separatedAmount();if(isRetired) return retiredAmount();return normalAmount();

}

ЗаменаЗамена условногоусловного оператораоператора полиморфизмомполиморфизмом((replace conditional with polymorphismreplace conditional with polymorphism))

double getSpeed(){

switch(type){

case EUROPEAN:return baseSpeed();

case AFRICAN:return baseSpeed()-

loadFactor()*cocunuts;case NOWWEGIAN_BLUE:

return isNailed ? 0 : baseSpeed(voltage);

}

throw new UnsupportedException("Unknown type, curerntly

unsupported");}

Когда: есть условный оператор, поведение которого зависит оттипа объекта

+getSpeed()

Bird

+getSpeed()

European

+getSpeed()

African

+getSpeed()

Norwegian Blue

Учебный Центр Luxoft www.luxoft.ru/edu

107

Page 108: Tdd Workbook

ВведениеВведение nullnull--объектаобъекта (introduce null object)(introduce null object)

if(customer==null) plan=BillingPlan.BASIC;

elseplan=customer.getPlan();

Когда: есть многкратные проверки на совпадение значения сnull.

ВведениеВведение утвержденияутверждения(introduce assertion)(introduce assertion)

Когда: некоторая часть кода предполагает определенноесотояние программы

double getExpenseLimit(){

return (expenceLimit != NULL_EXPENSE) ?expenceLimit :

primaryProject.getMemberExpenseLimit();}

double getExpenseLimit(){

Assert.isTrue(expenseLimit!=NULL_EXPENSE || primaryProject!=null);

return (expenceLimit != NULL_EXPENSE) ?expenceLimit :primaryProject.getMemberExpenseLimit();

}

УпрощениеУпрощение вызововвызовов

ПереименованиеПереименование методаметодаДобавлениеДобавление параметрапараметраУдалениеУдаление параметрапараметраРазделениеРазделение запросазапроса ии модификаторамодификатораПараметризацияПараметризация методаметодаЗаменаЗамена параметрапараметра явнымиявными методамиметодамиСохранениеСохранение целогоцелого объектаобъектаЗаменаЗамена параметрапараметра вызовомвызовом методаметодаВведениеВведение объектаобъекта--параметрапараметраУдалениеУдаление методаметода установкиустановки значениязначенияСокрытиеСокрытие методаметодаЗаменаЗамена конструктораконструктора фабричнымфабричным методомметодомИнкапсуляцияИнкапсуляция нисходящегонисходящего преобразованияпреобразования типатипаЗаменаЗамена кодакода ошибкиошибки исключениемисключениемЗаменаЗамена исключенияисключения проверкойпроверкой

Учебный Центр Luxoft www.luxoft.ru/edu

108

Page 109: Tdd Workbook

ПереименованиеПереименование методаметода ((rename method)rename method)

Когда: имя метода не раскрывает его назначения

ДобавлениеДобавление параметрапараметра (add parameter)(add parameter)

Когда: имя метода не раскрывает его назначения

УдалениеУдаление параметрапараметра (remove parameter)(remove parameter)

Когда: параметр больше не используется в теле метода

Учебный Центр Luxoft www.luxoft.ru/edu

109

Page 110: Tdd Workbook

РазделениеРазделение запросазапроса ии модификаторамодификатора ((separate query from separate query from modifiermodifier))

Когда: метод возвращает значение и изменяет состояниеобъекта

ПараметризацияПараметризация методаметода ((parametrizeparametrize methodmethod))

Когда: несколько методов выполняют сходные действия, но сразными значениями, содержащимися в теле метода

ЗаменаЗамена параметрапараметра явнымиявными методамиметодами ((replace parameter replace parameter with explicit methodswith explicit methods))

Когда: есть метод, выполняющий разный код в зависимости отзначения параметра перечисляемого типа

public void setValue(String name, int value){

if (name.equals("height"))height = value;

else if (name.equals("width"))width = value;

throw new UnsupportedOperationException("Unknownparameter.");

}

public void setHeigth(int value){

heigth = value;}

public void setWidth(int value){

width = value;}

Учебный Центр Luxoft www.luxoft.ru/edu

110

Page 111: Tdd Workbook

СохранениеСохранение целогоцелого объектаобъекта ((preserve whole preserve whole objectobject))

Когда: от объекта получаются несколько значений, которыепотом передаются в метод как параметры

Range range=daysTempRange();int low=range.getLow();int high=range.getHigh();

withinPlan = plan.withinPlan(low, high);

withinPlan = plan.withinPlan(dayTempRange());

ЗаменаЗамена параметрапараметра вызовомвызовом методаметода ((replace parameter replace parameter with methodwith method))

Когда: результат метода передается в качестве параметра вновый метод

int basePrice=quantity*itemPrice;discount=discountLevel();finalPrice = discountedPrice(basePrice, discount);

int basePrice=quantity*itemPrice;finalPrice = discountedPrice(basePrice);

public int discountedPrice(int basePrice){

dicount=discountLevel();........................

}

ВведениеВведение объектаобъекта--параметрапараметра ((introduce introduce parameter objectparameter object))

Когда: есть группа параметров, естественным образомсвязанных друг с другом

+amountInvoicedIn(in DateRange)+amountReceivedIn(in DateRange)+amountOverdueIn(in DateRange)

Customer

Учебный Центр Luxoft www.luxoft.ru/edu

111

Page 112: Tdd Workbook

УдалениеУдаление методаметода установкиустановки значениязначения ((remove setting remove setting methodmethod))

Когда: поле устанавливается в момент создания и большеникогда не меняется

СокрытиеСокрытие методаметода ((hide methodhide method))

Когда: метод не используется никаким другим классом

ЗаменаЗамена конструктораконструктора фабричнымфабричным методомметодом ((replace replace constructor with factory methodconstructor with factory method))

Когда: создание объекта подразумевает дополнительныедействия

Employee(int type){

this.type=type;}

static Employee create(int type){

if(type=ENGINEER)return new Engineer();

else if(type=SALESMAN)return new Salesman();

throw new IllegalArgumentException("Unknow employee type");}

Учебный Центр Luxoft www.luxoft.ru/edu

112

Page 113: Tdd Workbook

ИнкапсуляцияИнкапсуляция нисходящегонисходящего преобразованияпреобразования типатипа((encapsulate downcastencapsulate downcast))

Когда: метод возвращает объект, к которому клиент долженприменить нисходящее преобразование типа

Reading=(Reading)lastReading();

Object lastReading(){

return readings.lastElement();

}

Reading lastReading(){

return (Reading)readings.lastElement();}

ЗаменаЗамена кодакода ошибкиошибки исключениемисключением ((replace error code replace error code with exceptionwith exception))

Когда: метод возвращает особый код, представляющийошибку

int withdraw(int amount){

if (amount > balance)return -1;

else{

balance -= amount;return 0;

}}

void withdraw(int amount){

if (amount > balance)throw new BalanceException();

balance-=amount;}

ЗаменаЗамена исключенияисключения проверкойпроверкой ((replace replace exception with testexception with test))

Когда: выбрасывается исключение при невыполнениипредусловия

double getValueOfPeriod(int number){

try{

return values[number];}catch(ArrayIndexOutOfBound){

return 0;}

}

double getValueOfPeriod(int number){

if(number >= values.length)return 0;

return values[number];}

Учебный Центр Luxoft www.luxoft.ru/edu

113

Page 114: Tdd Workbook

ОбобщениеОбобщение

ПодъемПодъем поляполяПодъемПодъем методаметодаПодъемПодъем телатела конструктораконструктораСпускСпуск методаметодаСпускСпуск поляполяВыделениеВыделение подклассаподклассаВыделениеВыделение родительскогородительского классаклассаВыделениеВыделение интерфейсаинтерфейсаСвертываниеСвертывание иерархиииерархииФормированиеФормирование шаблонашаблона методаметодаЗаменаЗамена наследованиянаследования делегированиемделегированиемЗаменаЗамена делегированияделегирования наследованиемнаследованием

ПодъемПодъем поляполя (pull up field)(pull up field)

-nameEmployee

Salesman Engineer

Когда: в подклассах есть одинаковое поле

ПодъемПодъем методаметода ((pull up method)pull up method)

Employee

+getName()

Salesman

+getName()

Engineer

Когда: в подклассах есть методы с идентичными результатами

Учебный Центр Luxoft www.luxoft.ru/edu

114

Page 115: Tdd Workbook

ПодъемПодъем телатела конструктораконструктора ((pull up constructor pull up constructor bodybody))

Когда: имеются конструкторы с почти идентичными телами

public Manager(String name,String id,int grade){

this.name=name;this.id=id;this.grade=grade;

}

public Manager(String name,String id,int grade){

super(name, id);this.grade=grade;

}

СпускСпуск методаметода ((push down methodpush down method))

Когда: в родительском класса есть поведение, относящиесятолько к некоторым из подклассов

Employee

+getQuota()

Salesman Engineer

СпускСпуск поляполя ((push down field)push down field)

Employee

-quotaSalesman Engineer

Когда: есть поле, используемое лишь некоторымиподклассами

-quotaEmployee

Salesman Engineer

Учебный Центр Luxoft www.luxoft.ru/edu

115

Page 116: Tdd Workbook

ВыделениеВыделение подклассаподкласса ((extract subclassextract subclass))

Когда: в классе есть функции используемые только внекоторых случаях

+getTotalPrice()+getUnitPrice()

Job Item

+getUnitPrice()+getEmployee()

Labor Item

ВыделениеВыделение родительскогородительского классакласса ((extract extract superclasssuperclass))

Когда: имеются два класса со сходными функциями

ВыделениеВыделение интерфейсаинтерфейса

Когда: несколько клиентов пользуются одним и тем жеподмножеством интерфейса класса или в других классах частьинтерфейса является общей

+getRate()+hasSpecialSkill()

“interface”Billable

+getRate()+hasSpecialSkill()+getName()+getDepartment()

Employee

Учебный Центр Luxoft www.luxoft.ru/edu

116

Page 117: Tdd Workbook

СвертываниеСвертывание иерархиииерархии ((collapse hierarchycollapse hierarchy))

Когда: родительский класс и подкласс мало чем различаюся

ФормированиеФормирование шаблонашаблона методаметода ((form template methodform template method))

Когда: есть два метода в подклассах, выполняющиханалогичные шаги в одинаковом порядке, однако сами шагиразличны

+getBilling()+getTaxAmount()+getBaseAmount()

Site

+getBaseAmount()+getTaxAmount()

Residential Site

+getTaxAmount()+getBaseAmount()

Lifeline Site

return getBaseAmount()+getTaxAmount();

ЗаменаЗамена наследованиянаследования делегированиемделегированием ((replace replace inheritance with delegationinheritance with delegation))

Когда: подкласс использует только часть интерфейсародительского класса или не желает наследовать данные

Учебный Центр Luxoft www.luxoft.ru/edu

117

Page 118: Tdd Workbook

ЗаменаЗамена делегированияделегирования наследованиемнаследованием ((replace replace delegation with inheritancedelegation with inheritance))

Когда: вы пользуетесь делегированием и часто пишете многопростых делегирований для интерфейса в целом

ИнструментальныеИнструментальные средствасредства рефакторингарефакторинга

СС++++> XRefactory (Emacs, XEmacs)

> *nix, windows, mac> method extraction; > namespaces rename, > Class rename > Parameters rename, > Variables rename, > fields (structure records) and methods

(functions) rename> parameters insertion, deletion and moving.

ИнструментальныеИнструментальные средствасредства рефакторингарефакторинга (2)(2)

СС++++> Refactor! For Visual C++ 2005

> Add Block Delimiters> Case to Conditional> Conditional to Case> Create Overload> Encapsulate Field> Extract Method (in class)> Extract Function (outside of class)> Introduce Constant> Move Method to Header> Remove Block Delimiters> Reorder Parameters> Move Method to Source File> Reverse Conditional> Simplify Conditional> Widen Scope> Rename (namespace, type, members, parameters, locals, and

macros)

Учебный Центр Luxoft www.luxoft.ru/edu

118

Page 119: Tdd Workbook

ИнструментальныеИнструментальные средствасредства рефакторингарефакторинга (3)(3)

Delphi 2005Delphi 2005> Rename refactoring> Refactor driven “Find References”> Introduce Variable refactoring> Introduce Field refactoring> Inline Variable refactoring> Change Parameters refactoring> Safe Delete refactoring> Push Members Up / Down refactoring> Pull Members Up refactoring> Extract Superclass refactoring> Extract Interface refactoring> Move Members refactoring> Declare variable refactoring> Declare field refactoring> Extract method refactoring> Find unit/import namespace refactoring> Refactor driven “Find in Files”> Extract to resource string refactoring

ЛитератураЛитература

МартинМартин ФаулерФаулер, , ““РефакторингРефакторинг, , улучшениеулучшениесуществующегосуществующего кодакода””ДжошуаДжошуа КириевскиКириевски, , ““РефакторингРефакторинг ссиспользованиемиспользованием шаблоновшаблонов””СтивСтив МакконнеллМакконнелл, , ““СовершенныйСовершенный кодкод. . ПрактическоеПрактическое руководстворуководство попо разработкеразработкепрограммногопрограммного обеспеченияобеспечения””

ВопросыВопросы??

Q&AQ&A

Учебный Центр Luxoft www.luxoft.ru/edu

119

Page 120: Tdd Workbook

ПрактикумПрактикумУпражнениеУпражнение 33

UpUp--front design VS Simple designfront design VS Simple designПодходПодход TestTest--first + Refactoringfirst + Refactoring

ЕщеЕще разраз разработатьразработать приложениеприложение попо UseUse--case case диаграммедиаграмме, , ноно сс применениемприменением подходаподхода TestTest--first + first + RefactoringRefactoring

Test Driven DevelopmentTest Driven Development

СодержаниеСодержание

ОсновныеОсновные понятияпонятия ии принципыпринципы TDDTDDШаблоныШаблоны разработкиразработки тестовтестовОбщиеОбщие рекомендациирекомендацииЛитератураЛитература

Учебный Центр Luxoft www.luxoft.ru/edu

120

Page 121: Tdd Workbook

ЧтоЧто такоетакое unitunit--test?test?

ПрограммыПрограммы, , которыекоторые тестируюттестируют другиедругие программыпрограммы> маленькие> запускаются наборами> запускают кусок функционала в заданныхусловиях

> проверяют результат или поведение

unitunit--тестытесты техническитехнически

ПрограммнаяПрограммная средасреда длядля написаниянаписания юнитюнит--тестовтестов> написание тестов> утверждения> группировка тестов в наборыСредаСреда длядля запусказапуска> GUI> встраивание в цикл сборки> интеграция в IDEСС++++> CPPUnit

DelphiDelphi> DUnit

ЧтоЧто такоетакое TDDTDD??

ДисциплинаДисциплина разработкиразработки программногопрограммногообеспеченияобеспеченияПредсказуемыйПредсказуемый> вы знаете когда считать работу законченной> не беспокоитесь о нескончаемой чередеошибок

““ЧистыйЧистый кодкод, , которыйкоторый работаетработает””ВашиВаши коллегиколлеги могутмогут положитсяположится нана васвас, , аа вывы нананихнихТакойТакой кодкод писатьписать гораздогораздо приятнееприятнее ☺☺СпособСпособ ““управленияуправления страхомстрахом”” припри разработкеразработкепрограммногопрограммного обеспеченияобеспечения

Учебный Центр Luxoft www.luxoft.ru/edu

121

Page 122: Tdd Workbook

ПочемуПочему меняменя должнодолжно этоэто волноватьволновать??

НоНо ведьведь написаниенаписание тестовтестов этоэто дополнительныедополнительные затратызатратывременивремени??ДаДа, , иногдаиногда тестовоготестового кодакода большебольше чемчем работающегоработающего, , ноно::> вы имеет самотестирующийся код => меньше ошибок> при достаточно низкой плотности дефектов, QA командаможет перейти от реактивного тестирования кпревентивному

> уменьшается количество неприятных сюрпризов, менеджерам легче оценивать трудозатраты ипривлекать клиентов к совместной работе

> при низкой плотности дефектов – можно каждый деньполучать интегрированную стабильную сборку продукта

> вам легче делать рефакторинг и изменять код

TDD TDD –– этоэто длядля меняменя??

TDD TDD нене длядля васвас, , еслиесли> вам нравится лепить более-менее работающиекуски кода

> все заработало и вы надеетесь, что вам непридется возвращаться к этому коду вдальнейшем

TDDTDD длядля техтех::> у кого формируется эмоциональнаяпривязанность к коду

> кто считает, что чем чище код, тем вероятнееуспех

КакКак объяснитьобъяснить этоэто руководителюруководителю??

ПроблемаПроблема: : каккак убедитьубедить выделитьвыделить времявремя нананаписаниенаписание тестовтестов??ХорошийХороший руководительруководитель ((техническитехнически--грамотныйграмотный))> ориентирован на качествоРуководительРуководитель, , подгоняемыйподгоняемый графикомграфиком> не говорите> используйте как персональную практику, вывсе равно станете быстрее

Учебный Центр Luxoft www.luxoft.ru/edu

122

Page 123: Tdd Workbook

ЦиклЦикл разработкиразработки TDDTDD

красныйкрасный--зеленыйзеленый--рефакторингрефакторинг –– мантрамантра TDD TDD ((ритмритм))красныйкрасный -- напишитенапишите тесттест, , которыйкоторый нене работаетработаетилиили дажедаже нене компилируетсякомпилируетсязеленыйзеленый –– заставьтезаставьте тесттест работатьработать каккак можноможнобыстреебыстрее, , напишитенапишите ровноровно столькостолько, , чтобычтобы ононсработалсработалрефакторингрефакторинг –– удалитеудалите изиз написанногонаписанного всевседублированиедублирование

ШаблоныШаблоны

ШаблоныШаблоны разработкаразработка основаннойоснованной нана тестахтестахШаблоныШаблоны краснойкрасной полосыполосыШаблоныШаблоны тестированиятестированияШаблоныШаблоны зеленойзеленой полосыполосыШаблоныШаблоны xUnitxUnit

ШаблоныШаблоны разработкиразработки, , основаннойоснованной нана тестахтестах

ИзолированныйИзолированный тесттестСписокСписок тестовтестовВначалеВначале тесттестВначалеВначале утверждениеутверждение результатарезультатаТестовыеТестовые данныеданныеПонятныеПонятные данныеданные

Учебный Центр Luxoft www.luxoft.ru/edu

123

Page 124: Tdd Workbook

ИзолированныйИзолированный тесттест ((isolated test)isolated test)

КакимКаким образомобразом исполнениеисполнение одногоодного тестатеста должнодолжноповлиятьповлиять нана выполнениевыполнение другогодругого тестатеста??> Никаким.ПроблемаПроблема: : ломаетсяломается чточто--тото одноодно, , аа остальныеостальныетестытесты падаютпадают попо цепочкецепочке..ИзоляцияИзоляция позволяетпозволяет запускатьзапускать толькотолькоподмножествоподмножество тестовтестов, , аа нене всевсе..

СписокСписок тестовтестов ((test list)test list)

ЧтоЧто необходимонеобходимо тестироватьтестировать??ВыпишитеВыпишите всевсе тестытесты, , которыекоторые вамвам нужнонужно написатьнаписатьдлядля решениярешения сегодняшнихсегодняшних задачзадачЗафиксируйтеЗафиксируйте ихих вв видевиде пустыхпустых тестовтестов> не пишите реализацию тестов заранее

ВначалеВначале тесттест ((test firsttest first))

ВВ какойкакой моментмомент написатьнаписать тесттест??> перед тем как вы приступите к написаниюнового кода

TDD TDD –– методикаметодика формированияформирования дизайнадизайна вашеговашегоприложенияприложения> как будет использоваться ваш новый код> когда необходимо остановится

Учебный Центр Luxoft www.luxoft.ru/edu

124

Page 125: Tdd Workbook

ВначалеВначале утверждениеутверждение результатарезультата ((assertion assertion first)first)

СС чегочего начатьначать написаниенаписание тестатеста??> с оператора assert, который проверяетрезультат

> понимание того, что же будет в результате> начальная точка для размышленияСамоподобиеСамоподобие> с чего начать разработку системы – сформулировки требований

> с чего начать писать функционал – с теста

ТестовыеТестовые данныеданные ((test datatest data))

КакиеКакие данныеданные использоватьиспользовать длядля тестовтестов??> данные, которые делают тест понятными> думайте о других> если нет разницы между 124 и 1, используйте

1 – используйте осмысленные данныеРеалистичныеРеалистичные данныеданные> если вы тестируете реакция на внешниесобытия

> сравниваете вывод между версиямипрограммного обеспечения

> изменяете код, имитирующий реальныхпроцесс

ПонятныеПонятные данныеданные ((evident dataevident data))

КакКак отразитьотразить вв тестетесте назначениеназначение техтех илиили иныхиныхданныхданных??> добавьте в тест ожидаемый и реальныйрезультат и попытайтесь сделать отношениямежду ними понятными

> исключение по отношению к “магическимконстантам”

> облегчает программирование

Data now=new Date(NOVEMBER_15)Date result=scheduler.scheduleMeeting(now,

STANDARD_TOLERANCE,WEEKLY);

assertEquals(NOVEMBER_17,result);

Date result=scheduler.scheduleMeeting(november(15), 5, 7);assertEquals(november(17),result);

Учебный Центр Luxoft www.luxoft.ru/edu

125

Page 126: Tdd Workbook

ШаблоныШаблоны краснойкрасной полосыполосы

ОдношаговыйОдношаговый тесттестНачальныйНачальный тесттестТестТест –– объяснениеобъяснениеТестТест длядля изученияизученияЕщеЕще одинодин тесттестРегрессионныйРегрессионный тесттест

ОдношаговыйОдношаговый тесттест ((oneone--stepstep--testtest))

КакойКакой следующийследующий тесттест выбратьвыбрать изиз спискасписка??> который чему-либо научит вас> который вы сможете реализоватьНеНе делайтеделайте большиебольшие шагишагиЕслиЕсли нетнет тестовтестов, , которыекоторые можноможно реализоватьреализовать заза 1 1 шагшаг –– добавьтедобавьте новыеновыеВыВы всегдавсегда должныдолжны бытьбыть вв 1 1 шагешаге отот зеленойзеленойполосыполосы

НачальныйНачальный тесттест ((starter test)starter test)

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

ПриПри написаниинаписании реалистичногореалистичного тестатеста нужнонужноответитьответить нана слишкомслишком многомного вопросоввопросов::> Где должна располагаться операция> Какие входные данные – корректны> Каков должен быть результатОдинОдин тесттест –– одинодин ответответ

Учебный Центр Luxoft www.luxoft.ru/edu

126

Page 127: Tdd Workbook

ТестТест –– объяснениеобъяснение ((explanation test)explanation test)

КакКак распространитьраспространить вв командекоманде использованиеиспользованиеавтоматическогоавтоматического тестированиятестирования??> объясняя что-то, давайте тесты. Спрашивайтетесты у тех, кто пытается вам что-то объяснить

ТестТест длядля изученияизучения ((learning testlearning test))

КогдаКогда необходимонеобходимо писатьписать тестытесты длядля программногопрограммногообеспеченияобеспечения, , разработанногоразработанного стороннимистороннимиразработчикамиразработчиками??> перед тем как вы впервые воспользуетесьновыми возможностями

ВыВы пишитепишите тесттест, , которыйкоторый позволяетпозволяет вамвам убедитьсяубедитьсячточто API API работаетработает тактак каккак вывы ожидаетеожидаетеВыВы можетеможете производитьпроизводить тестированиетестирование нанасовместимостьсовместимость сс новыминовыми версиямиверсиями APIAPI

ЕщеЕще одинодин тесттест (another test)(another test)

КакКак предотвратитьпредотвратить уходуход мыслимысли отот основнойосновной темытемы??> добавьте постороннюю, интересную мысль всписок тестов и вернитесь к основной теме

Учебный Центр Luxoft www.luxoft.ru/edu

127

Page 128: Tdd Workbook

РегрессионныйРегрессионный тесттест ((regression testregression test))

ЧтоЧто сделатьсделать вв первуюпервую очередьочередь, , еслиесли былбылобнаруженобнаружен дефектдефект??> напишите самый маленький возможный тест, который его воспроизводит

> сделайте его зеленымПодумайтеПодумайте оо томтом каккак быбы вывы моглимогли узнатьузнать оонеобходимостинеобходимости написатьнаписать такойтакой тесттест додообнаруженияобнаружения дефектадефекта

ШаблоныШаблоны тестированиятестирования

ДочернийДочерний тесттестПоддельныйПоддельный объектобъектСамошунтированиеСамошунтированиеЛогиЛогиТестированиеТестирование обработкиобработки ошибокошибокСломанныйСломанный тесттестЧистыйЧистый комиткомит

ДочернийДочерний тесттест ((child test)child test)

КакКак заставитьзаставить работатьработать тесттест, , которыйкоторый получилсяполучилсяслишкомслишком большимбольшим??> напишите тест меньшего размера, которыйпредставляет собой сломанную часть большоготеста

> сделайте его зеленым> заново напишите большой тестВыВы сделалисделали слишкомслишком большойбольшой шагшаг> почему?> как надо было сделать, чтобы тест получилсяменьше?

Учебный Центр Luxoft www.luxoft.ru/edu

128

Page 129: Tdd Workbook

ПоддельныйПоддельный объектобъект ((mock objectmock object))

КакКак выполнятьвыполнять тестированиетестирование объектаобъекта, , которыйкоторыйбазируетсябазируется нана тяжеловесномтяжеловесном внешнемвнешнем ресурсересурсе? ? ИспользуйтеИспользуйте mockmock--объектыобъекты длядля эмуляцииэмуляцииповедениеповедение ресурсаресурса> Возможно потребует рефакторинга кода, чтобыбыла возможность подменить ресурс на mock-объект

Mock Mock объектыобъекты быстреебыстрееЛучшеЛучше читаютсячитаются вв тестетестеПозволяютПозволяют сделатьсделать изолированныйизолированный тесттест

СамошунтированиеСамошунтирование ((self shunt)self shunt)

КакКак убедитсяубедится, , чточто одинодин объектобъект корректнокорректновзаимодействуетвзаимодействует сс другимдругим??> заставьте тестируемый объектвзаимодействовать с вашим тестом

> возможно придется применить “извлечениеинтерфейса”

АльтернативаАльтернатива: : используйтеиспользуйте mockmock--объектыобъекты

СтрокаСтрока--логлог ((log string)log string)

КакКак убедитсяубедится, , чточто обращениеобращение кк методамметодампросиходитпросиходит вв правильномправильном порядкепорядке> создайте строку-лог в классе> каждый раз при обращении к методу, добавляйте к ней запись

АльтернативаАльтернатива: : используйтеиспользуйте mockmock--объектыобъекты

Учебный Центр Luxoft www.luxoft.ru/edu

129

Page 130: Tdd Workbook

ТестированиеТестирование обработкиобработки ошибокошибок ((crush test crush test dummy)dummy)

КакКак протестироватьпротестировать работуработу кодакода, , которыйкоторыйобрабатываетобрабатывает ошибкуошибку, , возникновениевозникновение которойкотороймаловероятномаловероятно??> создайте специальный mock объект, которыйвместо реально работы генерирует ошибку

СломанныйСломанный тесттест((broken test)broken test)

КакКак завершитьзавершить сеанссеанс программированияпрограммирования, , еслиесли вывыработаетеработаете вв одиночкуодиночку??> оставьте последний тест неработающимКогдаКогда вывы возвращаетесьвозвращаетесь кк работеработе сразусразу видитевидитегдегде вывы закончилизакончили, , ии вспоминаетевспоминаете оо чемчем думалидумали

ЧистыйЧистый комиткомит

КакКак следуетследует завершитьзавершить сеанссеанс программированияпрограммирования, , еслиесли вывы программируетепрограммируете вв командекоманде??> все ваши тесты должны работать передкоммитом

ЭтоЭто гарантируетгарантирует чточто системасистема находитсянаходится вв каждыйкаждыймоментмомент вв стабильномстабильном состояниисостоянии

Учебный Центр Luxoft www.luxoft.ru/edu

130

Page 131: Tdd Workbook

ШаблоныШаблоны зеленойзеленой полосыполосы

ПодделкаПодделкаТриангуляцияТриангуляцияОчевиднаяОчевидная реализацияреализацияОтОт одногоодного коко многиммногим

ПодделкаПодделка (Fake It)(Fake It)

ЕслиЕсли уу васвас естьесть сломанныйсломанный тесттест, , какойкакой должнадолжнабытьбыть самаясамая перваяпервая реализацияреализация??> сделайте чтобы метод возвращал константу> постепенно трансформируйте константу ввыражение с использованием переменных

ЗачемЗачем писатьписать ““ненужныйненужный”” кодкод??> Лучше хоть какой-то работающий код, чемвообще не работающий

> Психология – вы имеете зеленую полосу> Контроль на объемом работы (программистамсвойственно пере-проектирование)

ТриангуляцияТриангуляция ((triangulatetriangulate))

КакКак сформироватьсформировать абстракциюабстракцию сс помощьюпомощью тестовтестов??> добавьте несколько тестов с “подделкой”> попробуйте обобщить код

public void testSum() throws Exception{

assertEquals(4,plus(3,1) );

//one moreassertEquals(7,plus(3,4) );

}

public int plus(int a,int b){

return a + b;}

public void testSum() throws Exception{

assertEquals(4,plus(3,1) );}

public int plus(int a,int b){

return 4;}

Учебный Центр Luxoft www.luxoft.ru/edu

131

Page 132: Tdd Workbook

ОчевиднаяОчевидная реализацияреализация ((obvious obvious implementationimplementation))

КакойКакой способспособ подходитподходит длядля реализацииреализации простыхпростыхоперацийопераций??> просто реализуйте ихПодделкаПодделка ии ТриангуляцияТриангуляция позволяютпозволяют вамвамдвигатьсядвигаться маленькимималенькими шажкамишажками> но иногда вы абсолютно уверены какреализовать функционал

СледитеСледите каккак часточасто вывы сталкиваетесьсталкиваетесь сс краснойкраснойполосойполосой

ОтОт одногоодного коко многиммногим ((one to manyone to many))

КакКак реализоватьреализовать операциюоперацию, , котораякоторая работаетработает ссколлекциейколлекцией объектовобъектов??> реализуйте ее для одного объекта> затем модифицируйте для работы сколлекцией таких объектов

ШаблоныШаблоны xUnitxUnit

УтвержденияУтвержденияФикстураФикстураТестовыйТестовый методметодТестТест исключенияисключенияВсеВсе тестытесты

Учебный Центр Luxoft www.luxoft.ru/edu

132

Page 133: Tdd Workbook

УтвержденияУтверждения (assertion)(assertion)

КакКак убедитсяубедится чточто тесттест работаетработает корректнокорректно??> Используйте утверждения

public void testValidateQueue() throws Exception{

Result res= processor.validateQueue();

assertTrue(res.isValid());assertEquals(10,res.getStatusCode());

}

ФикстураФикстура

КакКак создаютсясоздаются ии освобождаютсяосвобождаются общиеобщие объектыобъекты ииресурсыресурсы, , используемыеиспользуемые вв тестахтестах??> конвертируйте локальные переменные в членыкласса теста

> используйте фикстуру для инициализации иосвобождения

ФикстураФикстура (2)(2)

private ByteCodeVirefier mockVerifier;private Processor processor;

public void setUp(){

mockVerifier = newMock(...);processor = new Processor(mockVerifier);

}

public void tearDown(){

resetMocks();}

public void testValidateQueue() throws Exception{

Result res = processor.validateQueue();

assertTrue(res.isValid());assertEquals(10, res.getStatusCode());

}

Учебный Центр Luxoft www.luxoft.ru/edu

133

Page 134: Tdd Workbook

ТестовыйТестовый методметод

ТестТест –– методметод, , имяимя которогокоторого содержитсодержит названиеназваниетестируемоготестируемого методаметода сс префиксовпрефиксов testtestОбычноОбычно располагаетсярасполагается вв томтом жежеpackage/namespacepackage/namespace чточто ии тестируемыйтестируемый класскласс

public void testValidateQueue() throws Exception{

Result res= processor.validateQueue();

assertTrue(res.isValid());assertEquals(10,res.getStatusCode());

}

ТестТест исключенияисключения (exception test)(exception test)

ТестируйтеТестируйте исключительныеисключительные ситуацииситуации> Перехватываете исключение, игнорируете его> Делаете сбой теста в нормальном потокеисполнения

public void testQueueFull() throws Exception {

try{

processor.validateQueue();fail("QueueFullException should be thrown");

}catch(QueueFullException e) {}

}

ВсеВсе тестытесты ((all tests)all tests)

КакКак запуститьзапустить всевсе ((группыгруппы) ) тестовтестов сразусразу??> используйте тестовые наборы

class IntegrationTests{

public static Test suite(){

TestSuite res = new TestSuite("Integration");res.addTestSuite(SystemATest.class);res.addTestSuite(SystemBTest.class);res.addTestSuite(SystemCTest.class);

return res;}

}

Учебный Центр Luxoft www.luxoft.ru/edu

134

Page 135: Tdd Workbook

КогдаКогда писатьписать тестытесты??

ПриПри добавлениидобавлении новойновой функциональностифункциональностиПриПри измененииизменении существующейсуществующей функциональностифункциональностиПриПри исправленииисправлении ошибкиошибкиЧтобыЧтобы разобратьсяразобраться вв неизвестномнеизвестном кодекодеПередПеред рефакторингомрефакторингом

НасколькоНасколько большимбольшим должныдолжны бытьбыть шагишаги??

КакойКакой объемобъем функциональностифункциональности должендолженпокрыватьпокрывать каждыйкаждый тесттест??> TDD поощряет маленькие шажки> но не следует доходить до маразма и писатьтест на каждую элементарную строчку

КакКак многомного требуетсятребуется промежуточныхпромежуточных стадийстадий длядлярефакторингарефакторинга??> зависит от инструментов> чем сложнее рефакторинг, тем больше шагов

СколькоСколько должнодолжно бытьбыть тестовтестов??

ОбычноОбычно тестовоготестового кодакода большебольше чемчем рабочегорабочегоВВ TDD TDD прагматичныйпрагматичный взглядвзгляд нана тестытесты> цель – работающий код, в корректностикоторого мы в достаточной степени уверены

> не пишите тест, если знание реализациипозволяет быть уверенным в корректности

ОценивайтеОценивайте среднеесреднее времявремя междумежду сбоямисбоями> Если система должна работать без сбоев до

100 лет, возможно требуется уделитьвнимание тестирование самых маловероятныхситуаций

Учебный Центр Luxoft www.luxoft.ru/edu

135

Page 136: Tdd Workbook

КогдаКогда удалятьудалять тестытесты??

ЧемЧем большебольше тестовтестов, , темтем лучшелучшеЕслиЕсли 2 2 тестатеста кажутсякажутся одинаковымиодинаковыми, , тото> не удаляйте тест, если это снижает вашууверенность в корректности поведениясистемы

> коммуникация. если другие члены командырассматривают два теста как разные сценарии, то не удаляйте тест.

ЛитератураЛитература

КентКент БекБек, , ““ЭкстремальноеЭкстремальное программированиепрограммирование. . РазработкаРазработка черезчерез тестированиетестирование..””http://www.testdriven.comhttp://www.testdriven.comhttp://www.mockobjects.com/http://www.mockobjects.com/

ВопросыВопросы??

Q&AQ&A

Учебный Центр Luxoft www.luxoft.ru/edu

136

Page 137: Tdd Workbook

ПрактикумПрактикумTDD WorkshopTDD Workshop

РазработкаРазработка приложенияприложения попо UseUse--case case диаграммедиаграмме ссиспользованиемиспользованием практикпрактик TDDTDD

ДвеДве итерацииитерации ии изменяющимисяизменяющимися требованиямитребованиямиПарнаяПарная разработкаразработкаШаблоныШаблоны TDDTDD

Учебный Центр Luxoft www.luxoft.ru/edu

137