Перемещение существующего кода в тестовую разработку

Недавно, обнаружив этот метод разработки, я считаю это довольно хорошей методологией. Итак, для моего первого проекта у меня есть небольшой код на DLL (в С#.NET, для чего он стоит), и я хочу сделать набор тестов для этого кода, но я немного потерял о том, как и с чего начать.

Я использую NUnit и VS 2008, любые советы о том, с какими классами начинать, что писать тесты и какие советы в целом о том, как продвигать код в тестовую основу, были бы весьма полезны.

Ответ 1

См. книгу Эффективная работа с устаревшим кодом от Michael Feathers.

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

Рефакторинг без тестов приведет к изменениям в поведении (т.е. ошибкам). И пуристы скажут, что это не рефакторинг из-за отсутствия тестов, чтобы проверить, что поведение не меняется.

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

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

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

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

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

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

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

Ответ 2

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

Я также нашел Test Driven Development на примере и Прагматическое тестирование модуля: в С# с NUnit - достойное введение в модульное тестирование в этой среде.

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

Ответ 3

Я называю это "Test Driven Reverse Engineering".

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

Когда вы делаете обычный TDD в прямом направлении, вы рассматриваете тест как священное и предполагаете, что код, вероятно, сломан. Иногда тест ошибочен, но ваше исходное положение - это код.

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

Затем вы можете выкопать код ошибки. Некоторые плохие кады будут иметь разумные тестовые примеры - это просто нужно очистить. Однако у некоторых плохих кодов есть тестовый пример, который бессмыслен. Это может быть ошибка или неуклюжий дизайн, который вы можете исправить.

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

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

Ответ 4

Тестовый код легко обнаружить - сопутствующими тестами. Если они есть, это должно быть проверено. Если их нет, допустим наоборот.;)

Это сказало: Test Driven Development (TDD) - это не столько стратегия тестирования, сколько стратегия дизайна. Тесты, которые вы пишете в первую очередь при разработке интерфейса ваших классов, а также в том, чтобы правильно охватить область ваших классов (или подсистем).

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

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

Ответ 5

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

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

Тесты на характеристики также обсуждаются в книге М. Персера "Эффективная работа с устаревшим кодом", которая рекомендуется в других ответах.

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