Я несколько оборонительный программист и большой поклонник контрактов Microsoft.
Теперь я не всегда могу использовать C #, и в большинстве языков единственный инструмент, который у меня есть, это утверждения. Поэтому я обычно получаю такой код:
class
{
function()
{
checkInvariants();
assert(/* requirement */);
try
{
/* implementation */
}
catch(...)
{
assert(/* exceptional ensures */);
}
finally
{
assert(/* ensures */);
checkInvariants();
}
}
void checkInvariants()
{
assert(/* invariant */);
}
}
Однако эта парадигма (или как бы вы ее ни называли) приводит к большому количеству помех в коде.
Я начал задаваться вопросом, действительно ли это стоит усилий и охватит ли это надлежащий модульный тест?
testing
code-contracts
ronag
источник
источник
Ответы:
Я не думаю, что вы должны думать об этом как "против".
Как упомянуто в комментариях @Giorgio, контракты кода должны проверять инварианты (в производственной среде), а модульные тесты должны гарантировать, что ваш код работает должным образом при соблюдении этих условий.
источник
Контракты помогают вам, по крайней мере, с одной вещью, которую не дают юнит-тесты. Когда вы разрабатываете публичный API, вы не можете тестировать модули, как люди используют ваш код. Однако вы все еще можете определить контракты для ваших методов.
Лично я бы так строго относился к контрактам только при работе с публичным API модуля. Во многих других случаях это, вероятно, не стоит усилий (и вместо этого вы можете использовать модульные тесты), но это только мое мнение.
Это не значит, что я советую не думать о контрактах в этих случаях. Я всегда думаю о них. Я просто не думаю, что необходимо всегда явно их кодировать.
источник
Как уже упоминалось, контракты и модульные тесты имеют различное назначение.
Контракты касаются защитного программирования, чтобы гарантировать выполнение предварительных условий, вызов кода с правильными параметрами и т. Д.
Модульные тесты, чтобы убедиться, что код работает, в разных сценариях. Это как «спецификации с зубами».
Утверждения хороши, они делают код устойчивым. Однако, если вы беспокоитесь о том, что он добавляет много кода, вы также можете добавить условные точки останова в некоторых местах во время отладки и уменьшить количество утверждений.
источник
Все, что у вас есть в вызовах checkVariants (), может быть сделано из тестирования, сколько усилий на самом деле может быть, зависит от многих вещей (внешних зависимостей, уровней связи и т. Д.), Но это очистит код с одной точки зрения. Насколько поддается проверке основанная на утверждениях кодовая база без какого-либо рефакторинга, я не уверен.
Я согласен с @duros, они не должны рассматриваться как исключительные или конкурирующие подходы. На самом деле в среде TDD можно даже утверждать, что утверждения «требования» должны будут иметь тесты :).
Утверждения, однако, НЕ делают код более надежным, если вы на самом деле не делаете что-то для исправления неудачной проверки, они просто останавливают повреждение данных или подобное, обычно прерывая обработку при первых признаках проблемы.
Тестируемое / хорошо протестированное решение обычно уже задумывалось и / или обнаруживало многие из источников / причин неправильных входных и выходных данных при разработке взаимодействующих компонентов и уже рассматривало их ближе к источнику проблемы.
Если ваш источник является внешним, и вы не можете его контролировать, чтобы избежать загромождения кода при решении других проблем с кодами, вы можете рассмотреть возможность реализации какого-либо компонента очистки / подтверждения данных между источником и вашим компонентом и поставить там свои проверки. ,
Кроме того, мне любопытно, на каких языках вы используете, у которых нет какой-либо xUnit или другой библиотеки тестирования, которую кто-то разработал, я думал, что в наши дни есть что-то для всего этого?
источник
В дополнение к модульным тестам и контрактам на код, я просто подумал, что выделю еще один аспект, который является ценностью при определении ваших интерфейсов, так что вы исключаете или уменьшаете возможность неправильного вызова кода в первую очередь.
Это не всегда легко или возможно, но определенно стоит задать себе вопрос: «Можно ли сделать этот код более надежным?»
Андерс Хейлсберг, создатель C #, сказал, что одной из самых больших ошибок в C # не было включение необнуляемых ссылочных типов. Это одна из главных причин, по которой существует столь необходимый беспорядок в защитном коде.
Тем не менее, рефакторинг для получения только необходимого и достаточного количества защитного кода делает, по моему опыту, более пригодным для использования и обслуживаемым кодом.
Согласитесь с @duros в остальном.
источник
Сделайте оба, но сделайте несколько статических вспомогательных методов, чтобы уточнить ваши намерения. Это то, что Google сделал для Java, посмотрите code.google.com/p/guava-libraries/wiki/PreconditionsExplained
источник