Конфликт NUnit с Debug.Assert

Я использую NUnit для написания модульных тестов для библиотеки, которую написал мой коллега. Его библиотека содержит множество Debug.Asserts, которые срабатывают при неверном вводе. Когда я пишу модульные тесты и ввожу недопустимые данные в его библиотеку, его Debug.Assert выдает окно сообщения, жалующееся на неверный ввод.

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

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

Какой "лучший" подход в этом случае?


person Nicholas    schedule 26.02.2010    source источник


Ответы (3)


Ознакомьтесь с документацией MSDN для метода Debug.Assert. В частности, в разделе «Примечания» объясняется, как отключить пользовательский интерфейс:

<configuration>
  <system.diagnostics>
    <assert assertuienabled="false" logfilename="c:\\myFile.log" />
  </system.diagnostics>
</configuration>

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

person Rob    schedule 26.02.2010

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

public class ProductionTraceListener : DefaultTraceListener
{
    public override void Fail(string message, string detailMessage)
    {
        string failMessage = message;

        if (detailMessage != null)
        {
            failMessage += " " + detailMessage;
        }

        throw new AssertionFailedException(failMessage);
    }
}

[Serializable]
public class AssertionFailedException : Exception
{
    public AssertionFailedException() { }
    public AssertionFailedException(string message) : base(message) { }
    public AssertionFailedException(string message, Exception inner) 
        : base(message, inner) { }
    protected AssertionFailedException(SerializationInfo info,
        StreamingContext context) : base(info, context) { }
}

И вы можете зарегистрировать его следующим образом:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <trace>
      <listeners>
        <clear />
        <add name="Default"
          type="[Namespace].ProductionTraceListener, [Assembly]" />
      </listeners>
    </trace>
  </system.diagnostics>
</configuration>

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

Мой совет — изменить код и использовать обычные if (x) throw ArgumentException() проверки предварительных условий (или использовать CuttingEdge.Conditions) и использовать те утверждает только для путей кода, которые никогда не должны запускаться. Также попробуйте использовать Trace.Assert вместо Debug.Assert, потому что вы также хотите, чтобы эти утверждения проверялись в вашей производственной среде. Когда вы это сделаете, вы можете использовать ProductionTraceListener в своей производственной среде, а это UnitTestTraceListener — в своих модульных тестах.

public class UnitTestTraceListener : DefaultTraceListener
{
    public override void Fail(string message, string detailMessage)
    {
        string failMessage = message;

        if (detailMessage != null)
        {
            failMessage += " " + detailMessage;
        }

        // Call to Assert method of used unit testing framework.
        Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Fail(
            failMessage);
    }
}

Удачи.

person Steven    schedule 26.02.2010
comment
Это выглядело бы хорошо для Trace.Assert(), но в ОП упоминается Debug.Assert(). - person Henk Holterman; 26.02.2010
comment
Кроме того, вы хотите, чтобы код терпел неудачу в модульных тестах при выполнении их как части автоматизированного процесса сборки. Утверждения предназначены для разработчиков во время выполнения кода. - person Rob; 26.02.2010
comment
@Henk && @Rob: Я не уверен, что понимаю тебя. Настройка ProductionTraceListener в среде модульного тестирования позволила бы модульным тестам завершиться ошибкой, если методы не выдавали ожидаемый AssertionFailedException. Когда модульные тесты запускаются в режиме отладки, все будет именно так, как он хочет, не так ли? Пожалуйста, просветите меня. - person Steven; 26.02.2010
comment
Стивен, Debug.Assert() — это плохо, потому что из-за него сборка Debug ведет себя иначе, чем сборка Release. Какое поведение вы хотите протестировать? - person Henk Holterman; 26.02.2010
comment
Хенк, именно поэтому я советую использовать Trace.Assert. Если отладочная сборка ведет себя иначе, это плохо. Я думаю, что мы думаем об этом одинаково. - person Steven; 28.02.2010

Простым вариантом, который я считаю эффективным, является использование стандартного ConsoleTraceListener, который позволит запускать проверки Debug.Assert, но направит их вывод на вкладку NUnit Text Output без какого-либо другого влияния на модульный тест.

Вы можете добавить это в свою тестовую настройку...

[SetUp]
public void SetUp()
{
    // Replace pop-up assert trace listener with one that simply logs a message.
    Debug.Listeners.Clear();
    Debug.Listeners.Add(new ConsoleTraceListener());
}

Только не забудьте проверить вывод текста, когда тест не пройден!

person yoyo    schedule 11.06.2014