Search code examples
c#unit-testingasynchronousevents

Unit Test for method that waits for asynchronous event


I want to test functionality inside of a method which waits for an external asynchronous event. Essentially like this:

private readonly AutoResetEvent resetEvent = new AutoResetEvent(false);

public async Task MyMethod()
{
    await otherComponent.DoSomething();
    otherComponent.Done += OnDone;
    resetEvent.WaitOne(MaxWait);
    otherComponent.Done -= OnDone;
    resetEvent.Reset();
}

private void OnDone(object sender, EventArgs e)
{
    resetEvent.Set();
}

otherComponent.DoSomething will in production trigger some asynchronous operations. After completion, Done will be raised. The method must wait until then. For the test, this component will be mocked. The test should ensure, that DoSomething was called and of course should finish properly.

My question is how to simulate this sort of behavior.

The only idea I have is to start a task before calling my test Method like below, but this seems rather hack to me as unit tests should not rely on thread scheduling.

Task.Run(async () =>
{
    await Task.Dely(250);
    otherComponentMock.RaiseDone
}
MyMethod
//Asserts

Solution

  • You could simply create a mock that runs the method synchronously:

    public class MyMockComponent(){
        public bool WasCalled {get; private set;}
        Task DoSomething(){
           WasCalled = true;
           return Task.CompletedTask;
        }
    }
    

    Depending on the type of method you might need to use Task.FromResult or TaskCompletionSource. I would try to avoid Task.Delay and Task.Run whenever possible, since that tend to make the tests less reliable.

    You should also be aware asynchronous code is just more difficult to test. Since there can be timing dependencies that are just difficult to cover well in unit tests. It is perfectly possible that some code passes the unit test, but deadlocks in the real world.