16

I am trying to write Xunit test on this method:

public async Task<IEnumerable<T>> RunSQLQueryAsync(string queryString)
{
    try
    {
        //do something
    }
    catch (DocumentClientException e)
    {
        throw new InvalidOperationException(e);
    }

}

Here's the unit test:

[Fact]
public async virtual Task Test_Exception()
{
    var queryString = "SELECT * FROM c";
    var exception = Record.ExceptionAsync(async () => await classname.RunSQLQueryAsync(queryString));
    Assert.NotNull(exception);
    Assert.IsType<DocumentClientException>(exception);
}

But the method failed and it says:

Message: Assert.IsType() Failure Expected: System.DocumentClientException Actual:
System.Threading.Tasks.Task`1[[System.Exception, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=xxx]]

When I debugged the test, it doesn't go to the catch block. So my question is how to make the unit test expects the method RunSQLQueryAsync to have DocumentClientException?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
superninja
  • 3,114
  • 7
  • 30
  • 63
  • 2
    you are not awaiting the task so the assertion is on the Task. `var exception = await Record.ExceptionAsync(async () => await classname.RunSQLQueryAsync(queryString));` – Nkosi Jul 26 '18 at 19:49
  • 1
    https://stackoverflow.com/questions/40828272/xunit-assert-throwsasync-does-not-work-properly – orhtej2 Jul 26 '18 at 19:49
  • More info in (another thread on SO)[https://stackoverflow.com/questions/45017295/assert-an-exception-using-xunit]. – LosManos Mar 03 '21 at 12:33

1 Answers1

23

The test is not awaiting the Task<Exception> returned from Record.ExceptionAsync so the following assertion is actually being done on the Task itself.

Also the method under test consumes the DocumentClientException and throws a new exception of InvalidOperationException so that is the type that should be expected.

[Fact]
public async virtual Task Test_Exception() {
    //Arrange
    var queryString = "SELECT * FROM c";

    //Act
    var exception = await Record.ExceptionAsync(() =>
        classname.RunSQLQueryAsync(queryString));

    //Assert
    Assert.NotNull(exception);
    Assert.IsType<InvalidOperationException>(exception);
}

Note the await before the Record.ExceptionAsync

The assumption is also that the class under test has been setup with a mocked dependency that will throw the desired exception in the //do something part of the provided snippet.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • hmm, it still doesn't go to the catch block. One confusion is that let's say the database or collection in cosmosdb that we connect to doesn't exist, then it will go to the catch block. But the unit test is not going to connect to the cosmosdb and find out they don't exist... – superninja Jul 26 '18 at 20:50
  • 1
    @WendyW. Provide more details about the method under test. Note my footnote about how the exception is being thrown. I have to make that assumption because there was no information in teh original question about how the exception is being thrown. – Nkosi Jul 26 '18 at 20:53
  • 1
    @WendyW. you are attempting to catch a specific exception. If that is not thrown then it wont get caught. – Nkosi Jul 26 '18 at 20:54