Search code examples
c#timeoutxunit.net

Xunit Timeout parameter: minimal working example


I'm trying to create a minimal working example of how the Timeout parameter in Xunit.net operates. I currently have the following Fact example, but it isn't operating as I expect, as it fails the test:

[Fact(Timeout = 50)]
public void FactTimeout_TimeoutLessThanProcessingTime_ThrowTestTimeoutException()
{
    // Arrange
    // Act
    Action act = () => Task.Delay(5000);

    // Assert
    Assert.Throws<TestTimeoutException>(act);
}

Is this correct, or is my understand wrong? Is there something else that needs to be changed or added to the test itself, or the Xunit config?

Update

Based on @RubenBartelink's answer I got the following to work:

// Will generate the exception and display it in the results window
[Fact(Timeout = 50)]
public async void TestOne() => await Task.Delay(5000);

// This will pass the test, but will complain that it is not awaited
[Fact(Timeout = 50)]
public void TestTwo() => Assert.ThrowsAsync<TestTimeoutException>(() => Task.Delay(5000));

Solution

  • You likely mean to use Assert.ThrowsAsync - otherwise you're measuring how long it takes to kick off the task (assuming the 50 means you intend to set a timeout of 50ms and you just want to prove it can indeed fail)

    While there are cases where you can avoid it, in general, I make such an async Test Method be async Task ... and ensure there is an await in there to make it easier to follow the flow (assuming Asyncness is key to your test)

    You may find discussion/examples in https://github.com/xunit/xunit/issues/217 useful


    EDIT: Example untested impl per your comment

    I'm trying to create a minimal working example of how the Timeout parameter in Xunit.net operates. I currently have the following Fact example, but it isn't operating as I expect, as it fails the test:

    [Fact(Timeout = 50)]
    public async Task FactTimeout_TimeoutLessThanProcessingTime_ThrowTestTimeoutException()
    {
        Action act = () => Task.Delay(5000);
    
        // Trigger the timeout by attempting something that will take too long
        await act;
    }
    

    this should internally result in a test timeout (the TestTimeoutException you were trying to catch). I suspect there won't be a neat way for you to catch the exception in question - if you need to observe and react to the timeout occurring and do something explicit (which you ideally want to avoid doing in a test), you'll need to explicitly manage that by doing a Task.WhenAny roughly like this:

    public async Task FactTimeout_TimeoutLessThanProcessingTime_ThrowTestTimeoutException()
    {
        Action act = () => Task.Delay(5000);
    
        let timeoutTask = Task.Delay(50);
        let res = await Task.WhenAny(timeoutTask, act);
    
        Assert.IsSame(timeoutTask, res);
    }
    

    NB this is only as an example to show that the timeout does happen and can be observed - the former approach with correct awaiting and letting xUnit manage the timeout without polluting the test with this sort of logic is where you want to arrive at.