NUnit 3.0 и Assert.Throws
Я пишу некоторые модульные тесты с NUnit 3.0 и, в отличие от v2.x, ExpectedException()
был удален из библиотеки.
Основываясь на этом ответе, я могу определенно увидеть логику в попытке поймать конкретно, где в тесте можно ожидать, что их система будет генерировать исключение (а не просто сказать "где-нибудь в тесте" ).
Тем не менее, я, как правило, очень подробно разбираюсь в своих процедурах Arrange, Act и Assert, и это создает проблему.
Я делал что-то вроде:
[Test, ExpectedException(typeof(FormatException))]
public void Should_not_convert_from_prinergy_date_time_sample1()
{
//Arrange
string testDate = "20121123120122";
//Act
testDate.FromPrinergyDateTime();
//Assert
Assert.Fail("FromPrinergyDateTime should throw an exception parsing invalid input.");
}
Теперь мне нужно сделать что-то вроде:
[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
//Arrange
string testDate = "20121123120122";
//Act/Assert
Assert.Throws<FormatException>(() => testDate.FromPrinergyDateTime());
}
Это не страшно, но, по-моему, мутит Закон и Assert. (Очевидно, для этого простого теста это не сложно, но может быть более сложным в более крупных тестах).
У меня был коллега, предлагающий полностью избавиться от Assert.Throws
и просто сделать что-то вроде:
[Test]
public void Should_not_convert_from_prinergy_date_time_sample3()
{
//Arrange
int exceptions = 0;
string testDate = "20121123120122";
//Act
try
{
testDate.FromPrinergyDateTime();
}
catch (FormatException) { exceptions++;}
//Assert
Assert.AreEqual(1, exceptions);
}
Здесь я придерживаюсь строгого формата AAA, но за счет еще большего раздувания.
Итак, мой вопрос выходит на тестеры типа AAA: как бы вы сделали какое-то тестирование проверки правильности исключения, например, я пытаюсь сделать здесь?
Ответы
Ответ 1
Я вижу, откуда вы пришли, хотя я не против сочетать шаги Act/Assert в этом случае.
Единственное, о чем я могу думать, это сохранить фактический делегат (здесь до FromPrinergyDateTime
) в переменную как шаг "act", а затем утвердить ее:
[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
//Arrange
string testDate = "20121123120122";
//Act
ActualValueDelegate<object> testDelegate = () => testDate.FromPrinergyDateTime();
//Assert
Assert.That(testDelegate, Throws.TypeOf<FormatException>());
}
Я понимаю, что шаг "act" не действует, а скорее определяет действие. Однако он четко определяет, какое действие тестируется.
Ответ 2
В С# 7 есть еще один вариант (хотя и очень похожий на существующие ответы):
[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
void CheckFunction()
{
//Arrange
string testDate = "20121123120122";
//Act
testDate.FromPrinergyDateTime();
}
//Assert
Assert.Throws(typeof(Exception), CheckFunction);
}
Сообщение в блоге по теме
Ответ 3
Вы можете создать настраиваемый атрибут в NUnit 3. Вот пример кода, как создать атрибут [ExpectedException]. (ExpectedExceptionExample Показывает, как реализовать пользовательский атрибут для NUnit)
https://github.com/nunit/nunit-csharp-samples