Не требует ли отладчик Unit Debug.Assert()?

Прошло некоторое время, когда я готов Mcconnell " Code Complete". Теперь я снова прочитал это в Ханте и Томасе "" Прагматический программист": используйте утверждения! Примечание. Нет утверждений о тестировании устройства, я имею в виду Debug.Assert().

После вопросов SO Когда следует использовать Debug.Assert()? и Когда использовать утверждение над исключениями в домене классы, полезны для развития, потому что "невозможные" ситуации могут быть найдены довольно быстро. И кажется, что они обычно используются. Насколько я понял утверждения, в С# они часто используются для проверки входных переменных для "невозможных" значений.

Чтобы максимально упростить и изолировать единичные тесты, я провожу классы и методы с помощью null и "невозможного" фиктивного ввода (например, пустую строку).

Такие тесты явно документируют, что они не полагаются на определенный вклад. Примечание. Я занимаюсь тем, что Meszaros "xUnit Test Patterns" описывает как Minimal Fixture.

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

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

Изменить: Лучшая практика для отладки Asserts во время модульного тестирования очень похожа, но она не отвечает на вопрос, который беспокоит меня: мне следует заботиться о Debug.Assert() в С#, если я тестирую, как я описал? Если да, то в какой ситуации они действительно полезны? В моей нынешней точке зрения такие Unit Tests не сделали бы Debug.Assert() ненужным.

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

Ответ 1

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

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

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

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

Ответ 2

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

IMO входы для твердого API должны быть защищены чеками, которые остаются на месте, независимо от типа сборки. Например, если публичный метод ожидает аргумент, который является числом от 5 до 500, он должен быть защищен с помощью исключения ArgumentOutOfRangeException. Быстрое завершение работы и отказ часто с использованием исключений, насколько я могу судить, особенно когда аргумент куда-то толкается и используется гораздо позже.

Однако в тех местах, где внутреннее, переходное состояние проверяется на работоспособность (например, проверяя, что какое-то промежуточное состояние находится в пределах разумных границ во время цикла), кажется, что Debug.Assert больше дома. Что еще вы хотели сделать, когда ваш алгоритм пошел не так, несмотря на то, что ему были переданы действительные аргументы? Выбросить исключение EpicFailException?:) Я думаю, что это где Debug.Assert по-прежнему полезно.

Я все еще не определился с лучшим балансом между ними. Я перестал использовать Debug.Asserts так много на С#, так как я начал модульное тестирование, но там все еще место для них IMO. Я, конечно, не использовал их для проверки правильности использования API, но проверка работоспособности в труднодоступных местах? Конечно.

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

Я думаю, что идея Unit Testing в этом случае состоит в том, чтобы перенести эти утверждения на тестовые примеры, чтобы убедиться, что вместо того, чтобы иметь Debug.Assert(...), ваш тестовый код обрабатывает его, не выкидывая (или обеспечивает что он правильно выбрасывается).