Игнорирование исключений в xUnit.net

У меня есть некоторые случаи, когда мне неважно, какое исключение выбрано (до тех пор, пока не будет выбрано какое-то исключение). К сожалению,

Assert.Throws<exception>(someDelegate);
</exception>

не проходит, если точно не создается экземпляр 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(); }
 );
}
</exception>
6 ответов

В документации здесь:

http://xunit.codeplex.com/wikipage?title=HowToUse&referringTitle=Home

Вы должны указать тип исключения, которое вы хотите бросить. В целом, это хорошая практика. Вы должны быть в состоянии предсказать, какие сценарии тест будет генерировать какой тип исключения. Вы должны иметь возможность проектировать как ваш метод, так и ваш тест таким образом, чтобы вы могли предсказать это.

Есть способы обойти это, например, делать попытку поймать себя, но вам нужно немного поменять свой дизайн.


Он не существовал во время этого вопроса, но теперь можно использовать Assert.ThrowsAny для проверки любого исключения, полученного из Exception (и, следовательно, любого исключения вообще), а также вариантов, таких как Assert.ThrowsAny который будет проверять любое исключение, полученное из ArgumentException и т.д.


Как вы определили, если Assert.Throws не соответствует счету, единственная вещь 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.


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;
}
</t>

Или:

public static bool Throws(this Action action)
{
 try
 {
 action.Invoke();
 }
 catch (Exception)
 {
 return true;
 }
 return false;
}


Я просто смотрел в источник 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))

Вы можете предложить подать патч?


public static void SuppressException<tsut>(this TSut value, Action<tsut> action) where TSut : class
 {
 try
 {
 action.Invoke(value);
 }
 catch (Exception)
 {
 //do nothing
 }
 }
</tsut></tsut>

licensed under cc by-sa 3.0 with attribution.