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

Игнорирование исключений в 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(); }
    );
}
4b9b3361

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