Unit-тестирование на энтузиазме
Кожевников Дмитрий
АКБ Росбанк
d.o.kozhevnikov@gmail.com
8-я конференция .NET разработчиков
6 апреля 2014
dotnetconf.ru
2Unit-тестирование на энтузиазме, Кожевников Дмитрий
Докладывает
• Кожевников Дмитрий Олегович
• .Net разработчик
• Инженер-программист, АКБ Росбанк
• Интересы: паттерны и практики разработки
качественного кода, unit-тестирование и TDD, новые
технологии в стеке .net, больше кода для бога кода
• Email d.o.kozhevnikov@gmail.com
3Unit-тестирование на энтузиазме, Кожевников Дмитрий
О чём я НЕ буду говорить
• Что такое unit-тесты и зачем?
• Как сделать код слабосвязным?
• Что за принципы SOLID?
• Как это - Inversion of Control?
• Программирование на основе интерфейсов?
4Unit-тестирование на энтузиазме, Кожевников Дмитрий
Перегруженные
unit-тесты
Большая инерция
кода
Тестируемость
вместо
простоты
5Unit-тестирование на энтузиазме, Кожевников Дмитрий
Нарушение
SRP
Много зависимостей
в классах
Тяжелые
алгоритмы
Инициализация
в конструкторе
6Unit-тестирование на энтузиазме, Кожевников Дмитрий
… и, как следствие
7Unit-тестирование на энтузиазме, Кожевников Дмитрий
Наши решения
ПРИНЦИПЫ
как Боб
Мартин
ЗАПАХИ
чем пахнет
наш код
8Unit-тестирование на энтузиазме, Кожевников Дмитрий
ПАТТЕРНЫ
прикладное
велосипедостроение
МЕТРИКИ
как будто и так
не видно
9Unit-тестирование на энтузиазме, Кожевников Дмитрий
Принципы
Для
тестов
Весь тест в
одном методе
Стабы, моки на лету по
полиморфным классам
Контроль объема
тестовых данных
10Unit-тестирование на энтузиазме, Кожевников Дмитрий
Для
тестируемых
классов
Тестирование концепции,
а не реализации
Объектная
декомпозиция
вместо структурной
Один вызов –
одно правило
Тестирование
изолированных
абстракций
Каждый вызов
оставляет след
11Unit-тестирование на энтузиазме, Кожевников Дмитрий
Паттерны
Список
команд
Шаг за
шагом
Нормальная
декомпо-
зиция
Отделение
инициа-
лизации
Контекст
для
вызовов
12Unit-тестирование на энтузиазме, Кожевников Дмитрий
13Unit-тестирование на энтузиазме, Кожевников Дмитрий
Нормальная декомпозиция
NormalDecomposition
PerformLogic();
IDependency1
MidResult1 SubAction();
IDependency2
MidResult2 SubAction(MidResult1 r);
IDependency3
MidResult3 SubAction(MidResult2 r);
14Unit-тестирование на энтузиазме, Кожевников Дмитрий
15Unit-тестирование на энтузиазме, Кожевников Дмитрий
Нормальная декомпозиция
+ -
Рост числа зависимостей
Расщепление логики
Число классов ограничено
Ценность абстракций
сомнительна
Интуитивность решения
Простой рефакторинг
16Unit-тестирование на энтузиазме, Кожевников Дмитрий
Шаг за шагом
StepsDirector
PerformLogic();
StepByStep
MidResult1 Step1();
MidResult2 Step2(MidResult1 r);
MidResult3 Step3(MidResult2 r);
StepByStep_Tests
Step1_Test();
Step2_Test();
Step3_Test();
17Unit-тестирование на энтузиазме, Кожевников Дмитрий
18Unit-тестирование на энтузиазме, Кожевников Дмитрий
19Unit-тестирование на энтузиазме, Кожевников Дмитрий
Шаг за шагом
+ -
Сложно выделить шаги
Страдает инкапсуляция
Промежуточные данные
Сохранение логики внутри
класса
Мало новых зависимостей
Можно выделить много
шагов
20Unit-тестирование на энтузиазме, Кожевников Дмитрий
Список команд
PerformLogic();
CommandsDirector ICommand
Execute(MidData data);
int SortOrder { get; }
Command1
Execute(MidData data);
int SortOrder { get; }
Command2
Execute(MidData data);
int SortOrder { get; }
21Unit-тестирование на энтузиазме, Кожевников Дмитрий
22Unit-тестирование на энтузиазме, Кожевников Дмитрий
Список команд
+ -
Нужен IoC-контейнер
Только для логики с
независимыми шагами
Важен порядок команд
Логика алгоритма разбросана
Скрыты детали реализации
Четкое разделение
ответственности
Расширяемость
23Unit-тестирование на энтузиазме, Кожевников Дмитрий
Много
шагов
Нужна
гибкость
Шаги
независимы
Логика в
одном
классе Нормальная
декомпозицияШаг за шагомСписок команд
Выделить
более крупные
шаги
-+
-
+
+
-
+-
24Unit-тестирование на энтузиазме, Кожевников Дмитрий
Отделение инициализации
InitializedObject
MidResult3 { get; set; }
Ctor(MidResult3 r,
IDependency3 service);
Initialize();
Action();
InitializedObject_Tests
Ctor_Test();
Initialize_Test();
Action_Test();
25Unit-тестирование на энтузиазме, Кожевников Дмитрий
26Unit-тестирование на энтузиазме, Кожевников Дмитрий
27Unit-тестирование на энтузиазме, Кожевников Дмитрий
Отделение инициализации
+ -
Ограничение
инкапсуляции состояния
класса
Дополнительный вызов
метода инициализации
Разгрузка тестов от
поддержки логики
конструктора
Разгрузка конструктора от
части зависимостей
28Unit-тестирование на энтузиазме, Кожевников Дмитрий
Контекст вызовов
Actor
Action1(IDependency1 d);
Action2(IDependency2 d);
Action3(IDependency3 d);
IDependency2
IDependency1
IDependency3
Facade
Action1();
Action2();
Action3();
WorkContext
Act<T>(Action<T> act);
TR Get<T,TR>(Func<T,TR> f);
ILocator
T Resolve<T>();
29Unit-тестирование на энтузиазме, Кожевников Дмитрий
30Unit-тестирование на энтузиазме, Кожевников Дмитрий
31Unit-тестирование на энтузиазме, Кожевников Дмитрий
+ -
Таки вариант
ServiceLocator
Чудной интерфейс
Разгрузка конструктора от
контекстных зависимостей
Контекст для логики (DCI?)
Контекст вызовов
32Unit-тестирование на энтузиазме, Кожевников Дмитрий
Много
заглушек и
глубокая
настройка в
Arrange
Дублирование
кода в Arrange
Вспомогательные
методы в
фикстурах
Защищённые
конструкторы
только для тестов
Тестовые
реализации
вместо моков
Зависимости
только для
конструктора
33Unit-тестирование на энтузиазме, Кожевников Дмитрий
Метрики по переменным:
34Unit-тестирование на энтузиазме, Кожевников Дмитрий
Метрики по настройкам
стабов/моков:
35Unit-тестирование на энтузиазме, Кожевников Дмитрий
Итоги
Разделение
ответственности -
необходимость, а
не искусство
Код определяет
качество тестов
Слабосвязный
дизайн !=
тестируемый
дизайн
Тестируемый
дизайн !=
простой дизайн
36Unit-тестирование на энтузиазме, Кожевников Дмитрий
Вопросы
Каков порог входа в
практики unit-
тестирования?
Как достигнуть
баланса между
тестируемостью и
простотой?
Оправдывают ли unit-
тесты усложнение
дизайна?
Нужны ли паттерны
тестируемого кода?
37Unit-тестирование на энтузиазме, Кожевников Дмитрий
Ссылки
• Антипаттерны TDD http://habrahabr.ru/post/43761/
• Те же посылки, но совсем другие решения, цикл статей,
Юрий Солдатенков
http://solyutor.blogspot.ru/2012/03/ock.html
• Тестируемый дизайн vs хороший дизайн, Сергей Тепляков
http://sergeyteplyakov.blogspot.ru/2013/04/vs.html
• Проект MockMetrics, R# плагин подсчёта метрик unit тестов
https://github.com/KozhevnikovDmitry/MockMetrics/tree/trunk
38Unit-тестирование на энтузиазме, Кожевников Дмитрий
Спасибо за внимание
Кожевников Дмитрий
АКБ Росбанк
d.o.kozhevnikov@gmail.com

Unit тестирование на энтузиазме