Что Для Вас Значат Модульные Тесты?

С технической точки зрения модульные тесты — это очень простой инструмент, основанный на нескольких простых концепциях: (1) тестируемый класс, (2) набор тестовых методов, заключенных в класс, и (3) набор методы, с помощью которых вы можете проверить, что состояние тестового класса соответствует (или не соответствует) некоторому значению.

Это очень простая вещь, которая может радикально повлиять на процесс разработки в целом.

С одной стороны, существует TDD («подход, ориентированный на тестирование»), при котором тесты «управляют» не только процессом кодирования, но и процессом проектирования (т. е.

проектирования системы).

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

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

Я привык думать о проектировании подсистемы с карандашом в руках, и мне слишком утомительно добавлять новый метод только после добавления теста.

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

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

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

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

Для меня юнит-тесты — это, прежде всего, «лакмусовая бумажка» хорошего дизайна.

Хороший дизайн обладает замечательными характеристиками: слабая связь и четкие отношения между классами и их клиентами.

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

Свойство 1. Модульные тесты положительно влияют на модульность и дизайн системы.

Проектируя систему, я часто задаю себе вопрос: «Хорошо, это отличная идея, но как мы собираемся ее протестироватьЭ» Если класс зависит от множества других классов, напрямую использует внешние ресурсы или берет на себя слишком большую ответственность, то тестирование этого класса будет невероятно трудным.

Я не большой поклонник проектирования ради дизайна или дизайна только ради тестируемости.

Но, как показывает практика, так далеко заходить не нужно: хороший проект системы достаточно слабо связан, чтобы покрыть тестами большинство ключевых частей системы (подробнее о влиянии юнит-тестов на проектирование и архитектуру можно прочитать в статье статья «Идеальная архитектура» ).

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

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

«Чистые методы» (то есть методы без побочных эффектов) идеальны с точки зрения модульного тестирования, поскольку они не зависят ни от чего, кроме своих аргументов, и не делают ничего, кроме возврата результата.

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

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

Свойство 2. Модульные тесты — отличный источник спецификации системы.

В одном из подкастов Кент Бек, отец JUnit, TDD и экстремального программирования, дал следующую характеристику юнит-теста: каждый юнит-тест должен рассказывать историю о тестируемом классе.

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

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

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

Это означает, что тест должен быть легко читаемым и поддерживаемым, иначе его жизнь закончится после первого сбоя.

Программисту, которому придется исправлять этот тест, будет проще снести его полностью вместо того, чтобы понимать, как работает это чудо.

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

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

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

Это баян, но тот факт, что все о нем знают, не делает наш код проще в сопровождении.

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

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

Свойство 4. Модульные тесты экономят наше время.

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

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

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

Помимо очевидных преимуществ в долгосрочной перспективе (легче поддерживать код, с помощью обычных тестов), есть и более «недальновидные» преимущества.

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

Звучит надуманно, но это значит, что либо вам повезло с вашими проектами, либо, наоборот, мне не повезло со своим.

В конце концов, большинство модульных тестов — это самый быстрый способ запустить или отладить поведение определенных классов.

Заключение Я не ярый поклонник модульных тестов, я не фанат TDD и не сторонник 100% покрытия.

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

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

Дополнительные ссылки 1. SERadio Эпизод 167: История JUnit и будущее тестирования с Кентом Беком 2. Кент Бек.

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

Настоятельно рекомендую! Теги: #.

NET #тестирование #юнит-тесты #тестирование ИТ-систем #программирование #проектирование и рефакторинг

Вместе с данным постом часто просматривают: