Тестирование Исключений с Помощью xUnit и Action
Когда вы пишете модульные тесты для метода, рекомендуется тестировать различные условия отказа («печальные пути») в дополнение к проверке того, что всё работает («счастливого пути»). В частности, если у вас есть метод, который может генерировать исключения, особенно если это пользовательские типы исключений, специфичные для вашего домена, вы должны быть уверены, что тестируете это поведение. Другой распространённый источник исключений - это защитные предложения, которые используются для поддержания чистоты вашего метода и обеспечения того, чтобы входные данные соответствовали ожиданиям метода.
В отличие от NUnit и MSTest, которые в основном используют атрибуты для ожидаемых исключений, xUnit предоставляет метод
Assert.Throws<T>, который используется для проверки ожидаемых исключений (в NUnit3 также появился аналогичный метод):Customer customer = null;
Assert.Throws<NullReferenceException>(
() => customer.LastName);
Кроме того, метод возвращает пойманное исключение, которое можно обработать:
var ex = Assert.Throws<NameRequiredException>(
() => customer.UpdateName("", ""));
Assert.Equal("Имя не задано", ex.Message);
Arrange, Act, Assert и Исключения
Многие тесты используют шаблон тестирования AAA (Arrange, Act, Assert – Настройка, Действие, Утверждение). Проблема с предыдущим примером в том, что перехват исключения метода относится как к блоку Act, так и к блоку Assert. Кроме того, эта строка получается слишком длинной.
В этом случае для строгого следования шаблону AAA делегат для
Assert.Throws можно выделить в отдельную переменную типа Action:[Fact]
public void ThrowsExceptionGivenInvalidName {
// Arrange
var customer = new Customer();
// Act
Action act = () => customer.UpdateName("", "");
// Assert
var ex = Assert.Throws<NameRequiredException>(act);
Assert.Equal("Имя не задано", ex.Message);
}
Теперь блок Действие явно содержит нужную операцию, а строка
Assert.Throws гораздо короче и понятнее.Заметьте также, что имя теста явно говорит о том, что тест выбрасывает исключение и при каких условиях.
FluentAssertions
Об этой библиотеке подробно было рассказано во вчерашнем видео. Если вы используете её, то код утверждения будет выглядеть примерно так:
[Fact]
public void ThrowsExceptionGivenInvalidName {
// …
// Assert
action.Should()
.Throw<NameRequiredException>()
.WithMessage("Имя не задано");
}
Источник: https://ardalis.com/testing-exceptions-with-xunit-and-actions/