NUnit, ни Assert.Throws, ни [ExpectedException] ловить выброшенное исключение
Прежде чем начать, я хочу прояснить, что я уже проверил решения как в этом вопросе, так и в этом вопросе.
Метод для тестирования
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)
);
}
Странное поведение
Ни одна из версий метода тестирования не улавливает 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 ответ
Я предполагаю, что вы на самом деле не тестируете тот код, который считаете нужным. Попробуйте положить немного Console.WriteLine
заявления и посмотреть, если они напечатаны. Если вы установите точку останова на throw
и запустите тесты в отладчике, точка останова попадет? Если управление передается следующему оператору, это означает, что исключение никогда не генерируется - его невозможно перехватить способом, который позволил бы продолжить выполнение в методе throwing, если вы не обнаружили действительно странную ошибку CLR.
Я написал много такого кода, и в NUnit его никогда не было.
Кроме того, я считаю хорошей практикой включать имя параметра в ArgumentExceptions, поэтому я бы написал:
if (connection == null)
{
throw new ArgumentNullException("connection");
}
if (sql == null)
{
throw new ArgumentNullException("sql");
}
К сожалению, возникает проблема, заключающаяся в том, что они заключаются в длинные строки и повторяют имена параметров в коде в виде строк... но это довольно легко сделать правильно (особенно с помощью ReSharper, помогающего проверять имена), и это может быть очень полезно, если это когда-нибудь сработает в производстве, (Есть несколько грязных хаков для проверки аргументов другими способами, но я подозреваю, что вы не хотите видеть эти...)