NUnit, ни Assert.Throws, ни [ExpectedException] ловить выброшенное исключение - PullRequest
1 голос
/ 21 января 2011

Прежде чем начать, я хочу прояснить, что я уже проверил решения как в этом вопросе , так и в этом вопросе .

Метод тестирования

public static DataSet ExecuteDataSet(this SqlConnection connection, string sql)
{
    if (null == connection || null == sql)
    {
        throw new ArgumentNullException();
    }

    using (var command = connection.CreateCommand())
    {
        // Code elided for brevity
    }
}

Методы испытаний

[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ExecuteDataSetThrowsForNullConnection()
{
    ((SqlConnection)null).ExecuteDataSet("SELECT TOP 1 * FROM prep");
}

[Test]
public void ExecuteDataSetThrowsForNullSql()
{
    Assert.Throws<ArgumentNullException>(
        () => Resource.Connection.ExecuteDataSet(null)
    );
}

Нечетное поведение

Ни то, ни другоеверсия метода test перехватывает ArgumentNullException, который выдается сразу после входа в метод ExecuteDataSet.Поток управления переходит к следующей строке (using (var command = connection.CreateCommand())), и вместо этого происходит NullReferenceException (что, конечно, не обрабатывается ни одним из моих тестовых случаев, потому что его никогда не следует выбрасывать ).

Первоначально первый метод испытаний (ExecuteDataSetThrowsForNullConnection) выглядел так же, как и второй (ExecuteDataSetThrowsForNullSql).Когда Assert.Throws не удалось поймать исключение, я провел некоторое исследование и заметил, что некоторые люди рекомендовали вместо него использовать ExpectedException.Я изменил тестовый код соответствующим образом, но безрезультатно.

Для записи это 32-битный код .NET 3.5, протестированный в NUnit 2.5.9.Я использую TestDriven.NET для интеграции с Visual Studio, и у меня установлены последние версии NCover и NDepend.

TL; DR Вопрос

Почему неметоды тестирования, перехватывающие выбрасываемое исключение и как его исправить?

РЕДАКТИРОВАТЬ

Эта версия метода тестирования работает.

[Test]
public void ExecuteDataSetThrowsForNullConnection()
{
    try
    {
        ((SqlConnection)null).ExecuteDataSet("SELECT TOP 1 * FROM prep");
    }
    catch(ArgumentNullException e)
    {
        Assert.AreEqual(true, true);
    }
    catch (Exception e)
    {
        Assert.Fail("Expected ArgumentNullException, but {1} was thrown instead.", e.GetType().Name);
    }
}

1 Ответ

3 голосов
/ 21 января 2011

Я предполагаю, что вы на самом деле не тестируете код, который вам кажется.Попробуйте ввести несколько Console.WriteLine операторов и посмотрите, напечатаны ли они.Если вы ставите точку останова в операторе throw и запускаете тесты в отладчике, получится ли точка останова?Если управление передается следующему оператору, это означает, что исключение никогда не генерируется - его невозможно перехватить таким способом, который позволил бы продолжить выполнение в методе throwing, если вы не нашли действительно странная ошибка CLR.

Я написал лотов кода, подобного этому, и он никогда не заканчивался в NUnit.

В целом, я считаю это хорошей практикой длявключите имя параметра в ArgumentExceptions, так что я бы написал:

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

К сожалению, возникает проблема, заключающаяся в длинном навинчивании и повторении имен параметров в коде в виде строк ... но это довольно просто получитьПравильно (особенно когда ReSharper помогает проверять имена), и это может быть очень полезно, если это когда-нибудь сработает в производстве.(Есть несколько безумных хаков для проверки аргументов другими способами, но я подозреваю, что вы не хотите их видеть ...)

...