NUnit: почему не утверждается. Бросает <T>Catch My ArgumentNullException? - PullRequest
15 голосов
/ 24 января 2011

Я снова отправляю этот вопрос по поручению уважаемого г-на Джона Скита, который предложил мне разработать простую тестовую программу, которая изолирует и демонстрирует проблему, с которой я столкнулся, и перепечатываю вопрос.Этот вопрос вырос из этого , поэтому, пожалуйста, прости меня, если все это звучит очень знакомо.Вы можете получить дополнительные сведения об этом вопросе из этого.

Проблема, с которой я сталкиваюсь Assert.Throws<T> из NUnit 2.5.9.В некоторых случаях он не сможет перехватить любых исключений, вызванных в методе, вызванном TestDelegate.Я закрепил это поведение в воспроизводимом коде ниже.(Хотя, по общему признанию, это может быть случай Fails On My Machine ™.

Чтобы воспроизвести ошибку, я создал решение с двумя проектами C # DLL:

  • сначала содержит один класс с одним открытым методом. Этот метод является методом расширения, который инкапсулирует логику, необходимую для создания SqlCommand, заполнения его параметров и вызова ExecuteScalar. Этот проект не содержит других ссылок.
  • Второй содержит один класс с двумя методами, которые проверяют, работает ли метод в первой DLL должным образом. Этот проект ссылается на первый и содержит ссылку на платформу NUnit. На другие сборки нет ссылок.

Когда я выполняю тесты в отладчике, я наблюдаю следующее:

  1. Assert.Throws правильно вызывает метод расширения ExecuteScalar<T>.
  2. Значения параметров, как и ожидалось, равны нулю.
  3. ExecuteScalar<T> проверяет свои параметры на наличие нулевых значений.
  4. Отладчик действительно запускает и выполняетстрока, содержащая throw new ArgumentNullException(...).
  5. После выполнения throw управление приложением не сразу передается Assert.Throws.Вместо этого он продолжается на следующей строке в ExecuteScalar<T>.
  6. . Как только выполняется следующая строка кода, отладчик прерывается и отображает ошибку «Аргумент нулевое исключение не было обработано кодом пользователя».

Исходный код, который изолирует это поведение, приведен ниже.

МЕТОД РАСШИРЕНИЯ

namespace NUnit_Anomaly
{
    using System;
    using System.Data;
    using System.Data.SqlClient;

    public static class Class1
    {
        public static T ExecuteScalar<T>(this SqlConnection connection, string sql)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            if (sql == null)
            {
                throw new ArgumentNullException("sql");
            }

            using (var command = connection.CreateCommand())
            {
                command.CommandType = CommandType.Text;
                command.CommandText = sql;
                return (T)command.ExecuteScalar();
            }
        }
    }
}

ТЕСТОВЫЕ СЛУЧАИ

namespace NUnit_Tests
{
    using System;
    using System.Data.SqlClient;
    using System.Diagnostics;

    using NUnit.Framework;

    using NUnit_Anomaly;

    [TestFixture]
    public class NUnitAnomalyTest
    {

        [Test]
        public void ExecuteDataSetThrowsForNullConnection()
        {
            Assert.Throws<ArgumentNullException>(() => ((SqlConnection)null).ExecuteScalar<int>(null));
        }

        [Test]
        public void ExecuteDataSetThrowsForNullSql()
        {

            const string server = "MY-LOCAL-SQL-SERVER";
            const string instance = "staging";
            string connectionString = String.Format("Data Source={0};Initial Catalog={1};Integrated Security=True;",
                                                    server,
                                                    instance);

            using (var connection = new SqlConnection(connectionString))
            {
                Assert.Throws<ArgumentNullException>(() => connection.ExecuteScalar<int>(null));
            }
        }
    }
}

Чистый эффект состоит в том, что тесты не выполняются, когда они не должны.Насколько я понимаю, Assert.Throws<T> должно поймать мое исключение, и тест должен пройти.

ОБНОВЛЕНИЕ

Я принял совет Гансаи проверил диалог Исключения.Я не нарушал сгенерированных исключений, но я нарушал необработанных пользовательских исключений.По-видимому, именно поэтому отладчик врывается в IDE при возникновении исключения.Снятие флажка устранило проблему, и Assert.Throws<T> поднял ее.Однако, если я этого не сделал, я не могу просто нажать F5, чтобы продолжить выполнение, или исключение станет NullReferenceException.

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

1 Ответ

15 голосов
/ 08 марта 2012

В действительности, Assert.Throws действительно перехватывает ваше исключение, однако Visual Studio все равно останавливается на исключении first-шанс . Вы можете проверить это, просто нажав F5; Visual Studio с радостью продолжит выполнение.

Как подсказывает вам помощник по исключениям, исключение было обработано кодом пользователя . Итак, мы знаем, что Visual Studio по какой-то причине не считает NUnit пользовательским кодом.

enter image description here

Visual Studio фактически говорит вам об этом в виде простого текста, если вы знаете, где искать:

enter image description here

Существует также доказательство этого факта в трассировке стека:

enter image description here

Решение 1 : Используйте отладочную сборку NUnit с символами отладки. Это заставит Visual Studio рассматривать NUnit как код пользователя и, таким образом, прекратить обрабатывать ваши исключения как «необработанные кодом пользователя». Это не тривиально, но может работать лучше в долгосрочной перспективе.

Решение 2 : снимите флажок «Включить только мой код» в настройках отладки Visual Studio:

enter image description here

P.S. Я не рассматриваю обходные пути, при которых вы вообще избегаете использования Assert.Throws<T>, но, конечно, есть способы сделать это.

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