Подтвердить что ты не робот

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: как бы вы сделали какое-то тестирование проверки правильности исключения, например, я пытаюсь сделать здесь?

4b9b3361

Ответ 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