Использовать метод NUnit Assert.Throws или атрибут ExpectedException?

146

Я обнаружил, что это два основных способа проверки исключений:

Assert.Throws<Exception>(()=>MethodThatThrows());

[ExpectedException(typeof(Exception))]

Какой из них будет лучше? Предлагает ли одно преимущество перед другим? Или это просто вопрос личных предпочтений?

SamuelDavis
источник
3
Третий вариант - свободный стиль:Assert.That(() => MethodThatThrows(), Throws.Exception)
Джек Уклея
1
NUnit версии 3 и более поздних версий больше не поддерживают ExpectedExceptionатрибут, поэтому для версии 3+ Assert.Throwsактуален только вариант.
Джоанлоф
Почему это так? Это Nunit3 решил отказаться от этой поддержки? Гуглил и не мог найти объяснения этому ... JUnit все еще поддерживает этот путь, не так ли?
ахаман

Ответы:

92

Первый позволяет тестировать более одного исключения с несколькими вызовами:

Assert.Throws(()=>MethodThatThrows());
Assert.Throws(()=>Method2ThatThrows());

Второе позволяет вам проверить только одно исключение для каждой тестовой функции.

чи х
источник
25
Тест должен проверять только один отдельный бит логики, поэтому не будет ли тестирование двух ошибок в одном модульном тесте плохой практикой?
SamuelDavis
5
@SamuelDavis - как правило, вы не хотите тестировать разные случаи в одном тесте. Тем не менее, может быть несколько вариантов использования для нескольких Assert.Throws.
че х
3
В любом случае, здесь вы получаете исключение в качестве параметра, который позволяет вам устанавливать детали в исключении. Кроме того, использование «Ожидаемого исключения» не защищает вас от того же типа исключения, которое выдается в другом вызове метода. Здесь вы нацелены на точный метод, а не на весь тест. Даже если ваш тест должен вызывать очень мало кода, вы никогда не будете в безопасности. Особенно, когда код становится сложным и / или исключение слишком общим. Такие вещи, как «ArgumentNullExceptions», могут быть выброшены много раз, и, например, их будет легко пропустить с помощью ExpectedException. Assert.Throws не пропустил бы это.
Гил Сэнд
254

Основным отличием является:

ExpectedException()Атрибут делает тест пройденным, если исключение происходит в любом месте в методе теста.
Использование Assert.Throws()позволяет указать exactместо кода, где ожидается исключение.

NUnit 3.0 полностью исключает официальную поддержку ExpectedException.

Поэтому я определенно предпочитаю использовать Assert.Throws()метод, а не ExpectedException()атрибут.

Александр Степанюк
источник
7
Это, безусловно, правильный ответ. Кстати, Assert.Throws () также возвращает исключение, что может позволить провести дополнительную проверку свойств исключения, если они имеют значение для вас.
перфекционист
1
Наконец, ответьте, почему я не могу получить ExpectedException для работы .. с версией 3.
JanT
2
Вот ссылка github.com/nunit/docs/wiki/Breaking-Changes - ExpectedExceptionAttribute больше не поддерживается.
Антон Лыхин
Чтобы изменить это для работы под NUnit 3.0, измените его на следующее
Андрей Красуцкий
38

Я предпочитаю assert.throws, поскольку он позволяет мне проверять и утверждать другие условия после возникновения исключения.

    [Test]
    [Category("Slow")]
    public void IsValidLogFileName_nullFileName_ThrowsExcpetion()
    {
        // the exception we expect thrown from the IsValidFileName method
        var ex = Assert.Throws<ArgumentNullException>(() => a.IsValidLogFileName(""));

        // now we can test the exception itself
        Assert.That(ex.Message == "Blah");

    }
Майк Пархилл
источник
Это один из лучших ответов, довольно часто вы хотите убедиться, что что-то вошло в состояние с ошибкой после возникновения исключения.
Рис Бевилаква
11

Вы также можете строго ввести ожидаемую ошибку (например, старую версию attrib).

Assert.Throws<System.InvalidOperationException>(() => breakingAction())
Преподобный Сфинкс
источник