Игнорирование исключений в xUnit.net
У меня есть некоторые случаи, когда мне неважно, какое исключение выбрано (до тех пор, пока не будет выбрано какое-то исключение). К сожалению,
Assert.Throws<Exception>(someDelegate);
не проходит, если точно не создается экземпляр Exception
(а не экземпляр производного класса). Я знаю, что могу получить поведение, которое я хочу с помощью
Exception exception = Record.Exception(someDelegate);
Assert.NotNull(exception);
но он не читается правильно. Я что-то пропустил в xUnit, который имеет поведение, которое я хочу? Вот два теста, которые показывают, что я имею в виду:
[Fact]
public void Throws_exception_and_passes() {
Exception exception = Record.Exception(
() => { throw new InvalidOperationException(); }
);
Assert.NotNull(exception);
}
[Fact]
public void Throws_exception_and_fails() {
Assert.Throws<Exception>(
() => { throw new InvalidOperationException(); }
);
}
Ответы
Ответ 1
В документации здесь:
http://xunit.codeplex.com/wikipage?title=HowToUse&referringTitle=Home
Вы должны указать тип исключения, которое вы хотите бросить. В целом, это хорошая практика. Вы должны быть в состоянии предсказать, какие сценарии тест будет генерировать какой тип исключения. Вы должны иметь возможность проектировать как ваш метод, так и ваш тест таким образом, чтобы вы могли предсказать это.
Есть способы обойти это, например, делать попытку поймать себя, но вам нужно немного поменять свой дизайн.
Ответ 2
Он не существовал во время этого вопроса, но теперь можно использовать Assert.ThrowsAny<Exception>
для проверки любого исключения, полученного из Exception
(и, следовательно, любого исключения вообще), а также вариантов, таких как Assert.ThrowsAny<ArgumentException>
который будет проверять любое исключение, полученное из ArgumentException
и т.д.
Ответ 3
xUnit не будет стоять на вашем пути, если вы хотите сделать свое собственное Custom Assertion, что-то вроде:
public static bool Throws<T>(this Action action, bool discardExceptions = false)
where T : Exception
{
try
{
action.Invoke();
}
catch (T)
{
return true;
}
catch (Exception)
{
if (discardExceptions)
{
return false;
}
throw;
}
return false;
}
Или:
public static bool Throws(this Action action)
{
try
{
action.Invoke();
}
catch (Exception)
{
return true;
}
return false;
}
Ответ 4
Как вы определили, если Assert.Throws<T>
не соответствует счету, единственная вещь OOTB в xUnit, с которой вы остались, использует Record.Exception
.
Как вы уже определили, основной способ сделать "Assert throws anything" - сделать
Assert.NotNull( Record.Exception( lambda ))
Посмотрите на это - не красиво. Это, вероятно, по дизайну; в xUnit.net очень мало вещей, которые случайно (в отличие от тщательно продуманного умиротворенного дизайна).
Record.Exception
возвращает результат по какой-либо причине (и если вы использовали F #, вам нужно |> ignore
отбросить значение). Вы всегда должны иметь возможность Assert
что-то о характере Исключения, которое происходит, так что фактическая проблема в вашем коде не будет проигнорирована случайно, так как вы меняете свой код с течением времени, что является причиной всего этого теста в первую очередь. Возможно, это может иметь форму
var exception = Record.Exception( sut.Something );
Assert.True( typeof(SomeException).IsAssignableFrom( exception ) );
Глядя на это, это безопаснее, чем Assert.NotNull()
, но все же не кажется правильным. Настало время, как обсуждалось в GOOS, слушать ваши тесты (и в случае уместной рамки тестирования, ваша тестовая среда).
Самая большая проблема в вашем вопросе заключается в том, что в реальном примере из реального теста всегда есть способ сделать ваш интерфейс более понятным или выразить свое ожидание по-другому, поэтому реальный ответ Mu.
Ответ 5
Я просто смотрел в источник xUnit.net и вот преступник:
private static Exception Throws(Type exceptionType, Exception exception)
{
Guard.ArgumentNotNull("exceptionType", exceptionType);
if (exception == null)
throw new ThrowsException(exceptionType);
if (!exceptionType.Equals(exception.GetType()))
throw new ThrowsException(exceptionType, exception);
return exception;
}
Что бы решить вашу проблему, если это изменение было применено:
if(!exceptionType.Equals(exception.GetType()))
в
if(!exception.GetType().IsAssignableTo(exceptionType))
Вы можете предложить подать патч?
Ответ 6
public static void SuppressException<TSut>(this TSut value, Action<TSut> action) where TSut : class
{
try
{
action.Invoke(value);
}
catch (Exception)
{
//do nothing
}
}