Должен ли я использовать Debug.Assert сегодня?

23

Недавно я натолкнулся на какой-то недавно написанный код, в который было добавлено множество Debug.Assert (C #).

Должны ли мы все еще использовать это широко, несмотря на использование TDD, BDD и модульного тестирования в целом?

Доминик Фрец
источник
9
Я не вижу, как одно исключает другое.
СуперМ
2
@superM Я определенно видел, как ленивые разработчики добавляли тесты в качестве утверждений, так как они писали свой код так, что было трудно смоделировать зависимости. Само собой разумеется, я не рекомендовал бы это
JK.

Ответы:

23

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

// Precondition using Asert
void SomeMethod(Foo someParameter)
{
    Debug.Assert(someParameter != null)
}

// Precondition using If-Then-Throw
void SomeMethod(Foo someParameter)
{
    if (someParameter == null)
        throw new ArgumentNullException("someParameter");
}

// Precondition using Code Contracts
void SomeMethod(Foo someParameter)
{
    Contract.Requires(someParameter != null);
}

// Precondition using some custom library
void SomeMethod(Foo someParameter)
{
    Require.ArgumentNotNull(() => someParameter);
}

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

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

[Test]
void SomeMethod_WhenGivenNull_ThrowsArgumentNullException()
{
    delegate call = () => someObject.SomeMethod(null);

    Assert.That(call).Throws<ArgumentNullException>();
}

Это совершенно другой вид утверждения ...

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

MattDavey
источник
10

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

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

vaughandroid
источник
5

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

Как указывает MattDavey, кодовые контракты могут быть лучше, обеспечивая статическую проверку вместо динамической проверки, и, если она недоступна, я бы предпочел Trace.Assert или просто старыйif(x) throw SomeException;

JK.
источник
4
Стоит отметить, что генерация кода с помощью Visual Studio в режиме выпуска приведет к тому, что все вызовы методов Debugкласса будут пропущены из компиляции ... поэтому подавление вызовов Assertпросто для производительности - это не просто преждевременная оптимизация, это просто бессмыслица.
Konamiman
@Konamiman в том-то и дело, я почти всегда хочу, чтобы в режиме релиза он тоже не получался:. Debug.Assert для меня бесполезен в 97% случаев
jk.
Тогда что это за 3%, @jk? Только старый код или какой-то другой экземпляр?
DougM
@DougM критический код производительности, это ссылка на цитату Кнута. Я также добавил бы, что я думаю, что ошибка с разбитым сердцем демонстрирует, что мое мнение является правильным, если у вас нет другого выбора, не исключайте проверки предварительных условий в вашем коде выпуска
jk.