Emil
Emil

Reputation: 73

Unit Tests - Assert.ThrowAnyAsync doesn't handle derived class of Exception Class (Xunit)

I have code like that:

var ex = await Assert.ThrowsAnyAsync<Exception>(async () => await _ftpClient.GetFile("test", "test"));

Method GetFile returns exception System.Net.Sockets.SocketException which is derived class of Exception class but ThrowsAnyAsync method doesn't work for it.

I received an error:

Assert.IsType() Failure
Expected: System.Exception
Actual:   System.Net.Sockets.SocketException

Do you have any idea why ?

Upvotes: 1

Views: 584

Answers (1)

Christopher Hamkins
Christopher Hamkins

Reputation: 1639

In the doc comments for Assert.ThrowsAsync in the xunit code (see current version 3 at https://github.com/xunit/assert.xunit/blob/main/ExceptionAsserts.cs) we can see:

/// Verifies that the exact exception is thrown (and not a derived exception type).

To also get derived types, the method Assert.ThrowsAnyAsync is provided

Doc comment:

/// Verifies that the exact exception or a derived exception type is thrown.

So you're correct to think that it should work in your case.

The Assert.ThrowsAnyAsync method eventually calls the following method which checks the type of the argument, exceptionType being the expected type, and exception being the actually thrown exception.

        static Exception ThrowsAny(
            Type exceptionType,
            Exception exception)
        {
            GuardArgumentNotNull(nameof(exceptionType), exceptionType);

            if (exception == null)
                throw new ThrowsException(exceptionType);

            if (!exceptionType.GetTypeInfo().IsAssignableFrom(exception.GetType().GetTypeInfo()))
                throw new ThrowsException(exceptionType, exception);

            return exception;
        }

If the IsAssignableFrom is returning true, then everything should work.

This short test code of mine

        public static bool testAssignable()
        {
            System.Net.Sockets.SocketException e = new SocketException();
            TypeInfo exceptionTypeInfo = typeof(Exception).GetTypeInfo();
            return exceptionTypeInfo.IsAssignableFrom(e.GetType().GetTypeInfo());
        }

returns true as expected, so it should® work...

This test passes:

        [Fact]
        public void Test()
        {
            var ex = Assert.ThrowsAnyAsync<Exception>(async () => await MUT());
        }

        private async Task MUT()
        {
            throw new System.Net.Sockets.SocketException();
        }

so it's working for me.

Your error message refers to Assert.IsType() failure. Are you checking the type yourself or is this message really coming from Assert.ThrowsAnyAsync?

There are some issues with Assert.IsType(), see xunit testing web api 2 controller : throws Xunit.Sdk.IsTypeException and XUnit issue https://github.com/xunit/xunit/issues/860 which was never fixed and "closed for age". Could that be the cause of your problem?

Upvotes: 3

Related Questions