среда, 19 февраля 2014 г.

Подводим "промежуточные" итоги о тестировании

Есть два поста:

"Всеволод Леонов задал правильные вопросы о тестировании" - http://programmingmindstream.blogspot.ru/2014/02/blog-post_15.html
"Как тестировать "вообще нетестируемое"" - http://programmingmindstream.blogspot.ru/2014/02/blog-post_4473.html

Они друг другу "несколько противоречат".

О чём вообще речь?

В первом посте приведён алгоритм - "как правильно вообще бы делать". Идти от ошибок, "пилить архитектуру" и делать её "тестируемой".
Во втором посте говорится о том "как вкрутить тесты ничего не меняя".

Почему так?

Скажем так - ПЕРВЫЙ путь он - БОЛЕЕ ПРАВИЛЬНЫЙ (с моей точки зрения).
А ВТОРОЙ - менее затратный.

Почему я предлагаю их оба?

Потому, что на самом деле я ОБА эти пути прошёл.

Поясню.

"Пилить архитектуру" и делать приложение "более тестируемым" - это конечно ХОРОШО.

Но! ЕСЛИ ТЕСТОВ нет, то ГДЕ ГАРАНТИЯ, что при "распиле архитектуры ничего не сломается"?

"Ручное протыкивание"?

ВАРИАНТ, но я обычно в него слабо верю. Особенно если "протыкивать" приходится МНЕ.

Я СЕБЕ - НЕ ДОВЕРЯЮ.

Что же делать?

Вот тут на сцену выходит ВТОРОЙ ВАРИАНТ.

Мы СНАЧАЛА - НИЧЕГО "не пилим", не трогаем АРХИТЕКТУРУ приложения. Ну "вся логика на формах", ну "Button.Click" - ПУСТЬ ТАК.

НИЧЕГО ПОКА НЕ ТРОГАЕМ.

ВНЕДРЯЕМ тесты в СУЩЕСТВУЮЩЕЕ ПРИЛОЖЕНИЕ.

И пишем их ТАК как СУЩЕСТВУЮЩЕЕ ПРИЛОЖЕНИЕ нам "диктует".

И пишем их ТАК как написано во ВТОРОМ посте. Вызывая Button.Click и считывая данные из контролов форм.

Это скажем так "наши контрольные точки". Отправные.

Итак.

Пишем тесты в ТАКОМ СТИЛЕ и убеждаемся, что ОНИ ПРОХОДЯТ.

Вторым пунктом - УБЕЖДАЕМСЯ, что тесты "хоть что-то проверяют".

При этом параллельно продолжаем нашу разработку.

И "время от времени" убеждаемся, что тесты "таки находят ошибки".

Это конечно НИЧТО НЕ ГАРАНТИРУЕТ. Но это "само по себе" - ПРИЯТНО.

Далее продолжаем писать ТЕСТЫ В ТАКОМ стиле и набираем их "некоторую критическую массу".

Которая "по нашим ощущения" говорит нам о том, что "многое из основных потоков" - ПРОТЕСТИРОВАНО.

Точнее - "покрыто тестами".

КОНЕЧНО это - "оценка на глазок".

Вот! Когда мы достигнем этой "критической массы" - можно переходить ко второй фазе.

Писать тесты уже ТРАНСФОРМИРУЯ архитектуру.

Т.е. под НОВЫЕ тесты АДАПТИРОВАТЬ АРХИТЕКТУРУ приложения, чтобы её было УДОБНО тестировать.

Применяя всяческие "критерии" (http://programmingmindstream.blogspot.ru/2014/02/blog-post_5990.html) и "паттерны" (типа Dependency Injection).

При этом ВАЖНО! После КАЖДОЙ ТРАНСФОРМАЦИИ архитектуры запускать ВЕСЬ КОМПЛЕКТ ТЕСТОВ.

При это ВАЖНО вот ещё что - надо ВАЛИДИРОВАТЬ те самые "первые тесты", которые мы написали БЕЗ ТРАНСФОРМАЦИИ архитектуры.

На предмет чего?

На предмет того - а не ВОЗМОЖНО ли их переписать уже с учётом СЛУЧИВШЕЙСЯ ТРАНСФОРМАЦИИ архитектуры, но БЕЗ УЩЕРБА качеству.

Если ВОЗМОЖНО, то их следует ПЕРЕПИСЫВАТЬ.

ДАЖЕ ТАК - на какой-то момент времени иметь ДВА НАБОРА таких тестов - "переисанные" и "изначальные".

И когда убеждаемся, что "переписанные" делают ТО ЖЕ САМОЕ, что и "изначальные" - удалять "изначальные", оставляя лишь "переписанные".

И?!

В КАКОЙ-ТО момент мы избавимся от "изначальных" тестов.

Которые дали нам "гарантию" от ошибок на "точке старта".

И придём к тому, что "тесты влияют на архитектуру" с одной стороны, а с другой - "архитектура влияет на тесты".

Получим систему с ОТРИЦАТЕЛЬНОЙ обратной связью (http://ru.wikipedia.org/wiki/%D0%9E%D1%82%D1%80%D0%B8%D1%86%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BE%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D0%B0%D1%8F_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C).

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

Система будет не РАСКАЧИВАТЬСЯ (как упомянуто тут - http://18delphi.blogspot.ru/2013/03/blog-post.html), а СТАБИЛИЗИРОВАТЬСЯ.

Ошибки в тестах вылезут в РЕАЛЬНОМ КОДЕ, а ошибки в коде - вылезут в тестах.

И в этот момент можно будет сказать - "да наша система - ТЕСТИРУЕМА". (Понятное дело, что "на столько-то процентов").

Мысль понятна?

1. СНАЧАЛА пишем "хоть какие-то тесты", которые "хоть что-то проверяют".
2. Убеждаемся, что они НИЧЕГО НЕ СЛОМАЛИ (пусть и ручным протыкиванием). Этот шаг - ОЧЕНЬ ВАЖЕН.
3. УБЕЖДАЕМСЯ, что тесты "проверяют то, что нужно".
4. Набираем "критическую массу" таких тестов.
5. Начинаем писать "новые" тесты, "подтачивая архитектуру".
6. При этом проверяем ВЕСЬ комплект тестов.
7. Время от времени пишем замену "изначальным" тестам.
8. Время от времени удаляем "изначальные" тесты для которых есть замена.
9. В какой-то момент "изначальных" тестов - НЕ ОСТАЁТСЯ.
10. Получаем систему с ОТРИЦАТЕЛЬНОЙ ОБРАТНОЙ СВЯЗЬЮ.

И далее рекурсия - "тесты влияют на архитектуру (и код)", а "архитектура (и код) - влияют на тесты".

Ну и далее можно пойти "на новый виток" - тесты влияют на код, тесты влияют на ТЗ, ТЗ влияет на тесты и ТЗ влияет на код.

Но это уже "в следующих сериях".

Как "применить всё это на практике"?

В БЛИЖАЙШЕЕ время я думаю, что я смогу начать публиковать код - http://programmingmindstream.blogspot.ru/2014/02/rumtmarc.html

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

3 комментария:

  1. прочел, осознал, согласен, думал о том же. Выложил свои мысли руководству, сказали закончить проект. Поставил дома ХЕ5 пытаюсь вначале хотя бы проект перевести на это дело. Щас с компонентами воюю. Хочу запустить проекты по ХЕ5. И начать "крутить" Ходжа с LiveBindigs и MVVM. Понял что пошел не с того конца. Спасибо. Будем писать Тест-фреймворк. Вы смотрели на DUNITX ?

    ОтветитьУдалить
    Ответы
    1. "Понял что пошел не с того конца."

      Было бы здорово, если бы Вы "по итогам" отписались бы - "какой конец правильный".

      Удалить