Почему рекомендуется всегда выполнять модульное тестирование наименьшей возможной единицы кода? Я считаю, что эти тесты никогда не переживут рефакторинг - PullRequest
11 голосов
/ 18 сентября 2009

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

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

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

Кто-нибудь еще имеет подобные или противоположные переживания?

Ответы [ 6 ]

10 голосов
/ 18 сентября 2009

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

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

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

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

2 голосов
/ 18 сентября 2009

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

2 голосов
/ 18 сентября 2009

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

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

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

1 голос
/ 19 сентября 2009

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

1 голос
/ 18 сентября 2009

Не похоже, что вы делаете правду Разработка через тестирование , которая требует итеративного цикла написания теста для небольшого фрагмента функциональности, создания функциональности для его выполнения и рефакторинг для удаления любого дублирования, которое мог добавить тест / код. Похоже, что вы тестируете после факта («код всегда достаточно сильно меняется, чтобы небольшие модульные тесты просто отбрасывались»). Если тест является спецификацией функциональности (как в TDD), рефакторинг никогда не приведет к тому, что тест «не выживет».

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

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

Я рекомендую вам следовать практике TDD, как описано в Кент Бек . Написание тестов по факту лучше, чем отсутствие тестов, но я считаю, что это гораздо менее продуктивная практика, чем TDD.

1 голос
/ 18 сентября 2009

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

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

Ошибка, внесенная во время рефакторинга внутреннего алгоритма вашего класса, нарушает 90% временных тестов на семантическом уровне, и в большинстве случаев, если вы тестируете часто и рано, ошибка обнаруживается быстро.

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