jason
jason

Reputation: 241769

Ignoring Exceptions in xUnit.net

I have some cases where I don't care what exception is thrown (as long as some exception is thrown). Unfortunately,

Assert.Throws<Exception>(someDelegate);

doesn't pass unless exactly an instance of Exception (so not an instance of a derived class) is thrown. I know I can obtain the behavior I want with

Exception exception = Record.Exception(someDelegate);
Assert.NotNull(exception);

but it doesn't read right. Am I missing something in xUnit that has the behavior I want? Here are two tests that indicate what I mean:

[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(); }
    );
}

Upvotes: 14

Views: 8603

Answers (6)

Nobody
Nobody

Reputation: 4841

xUnit won't stand in your way if you want to do your own Custom Assertion, something like:

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

Or:

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

Upvotes: 2

Ryan.Bartsch
Ryan.Bartsch

Reputation: 4210

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

Upvotes: 0

Jon Hanna
Jon Hanna

Reputation: 113352

It didn't exist at the time of this question, but now one can use Assert.ThrowsAny<Exception> to test for any exception derived from Exception (and hence any exception at all), along with variants such as Assert.ThrowsAny<ArgumentException> which would test for any exception derived from ArgumentException and so on.

Upvotes: 5

Ruben Bartelink
Ruben Bartelink

Reputation: 61895

As you've identified if Assert.Throws<T> doesn't fit the bill, the only OOTB thing in xUnit you're left with is using Record.Exception.

As you've identified, the main way of doing a 'Assert throws anything` is to do

Assert.NotNull( Record.Exception( lambda ))

Look at it - not pretty. This is likely by design; there are very few things in xUnit.net that are by accident (as opposed to carefully considered opinionated design).

Record.Exception returns a result for a reason (and if you were using F#, you'd have to |> ignore to chuck away the value). You should always be able to Assert something about the nature of the Exception that's happening so that an actual problem in your code doesn't get ignored by chance as you change your code over time, which is the reason for all this testing stuff in the first place. Perhaps that might take the form of

var exception = Record.Exception( sut.Something );
Assert.True( typeof(SomeException).IsAssignableFrom( exception ) );

Looking at that, it's safer that an Assert.NotNull(), but still doesn't feel right. It's time to, as discussed in GOOS, listen to your tests (and in the case of an opinionated test framework, your test framework).


The biggest problem in your question is however that in a real example from a real test, there is always a way to make your interface clearer or express your expectation in another way, so the real answer is Mu.

Upvotes: 2

justin.m.chase
justin.m.chase

Reputation: 13685

I was just looking in the xUnit.net source and here is the culprit:

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

What would solve your problem is if this change were applied:

if(!exceptionType.Equals(exception.GetType()))

to:

if(!exception.GetType().IsAssignableTo(exceptionType))

You could possibly offer to submit a patch?

Upvotes: 1

poindexter12
poindexter12

Reputation: 1793

Per the documentation here:

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

You have to specify the type of exception you want to be thrown. In general, this is good practice. You should be able to predict what scenarios a test would throw what type of exception. You should be able to design both you method and your test in a way that will allow you to predict this.

There are ways around this, like doing a try catch yourself, but you should look into changing your design a bit.

Upvotes: 8

Related Questions