Лучший вариант для ретроспективного применения TDD в кодовой базе C # - PullRequest
5 голосов
/ 10 октября 2011

У меня есть существующий фреймворк, состоящий из 5 библиотек C #, этот фреймворк хорошо используется с 2006 года и является основной базой кода для большинства моих проектов. Моя компания хочет развернуть TDD по соображениям качества программного обеспечения; Проработав много уроков и прочитав теорию, я понимаю преимущества TDD.

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

A) Один тестовый проект может использоваться для перекрытия объектов из всех 5 компонентов библиотеки. Ряд высокоуровневых тестов может стать отправной точкой для того, что впервые рассматривается как очень большая библиотека программного обеспечения.

B) Тестовый проект для каждого из 5 компонентов библиотеки. Проекты будут тестировать функции на самом низком уровне в изоляции от других компонентов библиотеки.

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

Какой бы вариант не был выбран, для замены внешних зависимостей может потребоваться «Пересмешка», например:

  • База данных
  • Веб-сервис
  • Файлы конфигурации

Если у кого-то есть еще вход, это было бы очень полезно. Я планирую использовать встроенный Microsoft MSTest в Visual Studio 2010.

Ответы [ 5 ]

6 голосов
/ 10 октября 2011

У нас есть основанная на миллионах строк кодовая база.Наш подход состоял в том, чтобы начать с написания некоторых интеграционных тестов (ваш вариант A).Эти тесты выполняют почти всю систему полностью: они копируют файлы базы данных из репозитория, подключаются к этой базе данных, выполняют некоторые операции с данными, а затем выводят отчеты в CSV и сравнивают их с заведомо исправным выводом.Они далеко не исчерпывающие, но они выполняют множество задач, которые наши клиенты полагаются на наше программное обеспечение.

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

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

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

5 голосов
/ 10 октября 2011

Ни (A), ни (B) не могут рассматриваться как TDD. Код уже написан; новые тесты не будут приводить его дизайн. Это не означает, что нет никакого смысла в продвижении по любому из этих путей, но было бы ошибкой считать их TDD. Что касается «кода, который широко считается работающим», я подозреваю, что если бы вы начали (B), вы бы обнаружили в нем некоторые дыры. Непроверенный код почти всегда содержит ошибки.

Моим советом было бы следовать (B), потому что я нахожу большую ценность в модульных тестах, чем в интеграционных тестах (хотя большая часть этого большего значения заключается в преимуществах конструкции, для которых вы опоздали). Интеграционные тесты также полезны и могут рассказать вам о важных вещах вашего кода, но я бы хотел начать с модульных тестов. Выберите один из 5 компонентов и начните писать то, что мы называем характеристическими тестами . Начните изучать поведение, накапливайте опыт написания юнит-тестов. Выберите самые простые вещи для тестирования в первую очередь; опирайтесь на то, что вы изучаете, с помощью простых методов постепенного наращивания, чтобы проверить хитрые биты. При написании этих тестов характеристик вы почти наверняка обнаружите удивительное поведение. Обязательно обратите на это внимание и подумайте над тем, нужно ли это исправлять (или исправления могут нарушать код, основанный на неожиданном поведении).

И, конечно, пишите тесты для любых новых функций или исправлений ошибок до кода, который их реализует. Удачи!

3 голосов
/ 10 октября 2011

По определению, если вы создаете тесты для существующей кодовой базы, это не TDD.

Я бы взял C) как данность: всякий раз, когда у вас есть ошибка, напишите тест, который «доказывает» ошибку, и отмените ее навсегда.

Я согласен с советами Карла Манастера.Другой аспект в этом вопросе - «экономика»: написание тестов для унаследованного приложения может быть дорогостоящим, так где же вы получите максимальную отдачу от затраченных средств?Подумайте об а) классах и методах, которые наиболее часто используются, б) о классах и методах, которые с наибольшей вероятностью имеют ошибку (обычно те, которые имеют наибольшую сложность кода).

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

0 голосов
/ 10 октября 2011

Опции A и B не соответствуют определению TDD, и оба довольно трудоемки.Я бы выбрал вариант C, потому что это наиболее прагматичное решение.

0 голосов
/ 10 октября 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...