lundi 19 janvier 2015

Test that task is being awaited

I have the following code which i'd like to test:



private Task _keepAliveTask; // get's assigned by object initializer

public async Task EndSession()
{
_cancellationTokenSource.Cancel(); // cancels the _keepAliveTask
await _logOutCommand.LogOutIfPossible();
await _keepAliveTask;
}


It is important that the EndSession Task only ends once the `_keepAliveTask' ended. However, i'm struggling to find a way to test it reliably.


non-async method


If there wouldn't be the call to _logOutCommand.LogOutIfPossible() it would be quite simple: i'd just remove the async and return _keepAliveTask instead of awaiting it:



public Task EndSession()
{
_cancellationTokenSource.Cancel();
return _keepAliveTask;
}


non-async method, sync over async


Of course, i could do something similar:



public Task EndSession()
{
_cancellationTokenSource.Cancel(); // cancels the _keepAliveTask
_logOutCommand.LogOutIfPossible().Wait();
return _keepAliveTask;
}


But that is a no-go (sync over async).


observing effects instead of verifying calls


Now of course instead of "unit" testing method calls etc. i could always observe effects. Which is: As long as _keepAliveTask hasn't ended the EndSession Task mustn't end either. But since i can't wait indefinite one has to settle for a timeout. The tests should be fast so a timeout like 5 seconds is a no go. So what i've done is:



[Test]
public void EndSession_MustWaitForKeepAliveTaskToEnd()
{
var keepAlive = new TaskCompletionSource<bool>();
_cancelableLoopingTaskFactory
.Setup(x => x.Start(It.IsAny<ICancelableLoopStep>(), It.IsAny<CancellationToken>()))
.Returns(keepAlive.Task);

_testee.StartSendingKeepAlive();

_testee.EndSession()
.Wait(TimeSpan.FromMilliseconds(20))
.Should().BeFalse();
}


But i really really dislike this approach. It's hard to understand and it's unreliable.


So is there any reliable way to verify that an async method is awaiting a task?


Aucun commentaire:

Enregistrer un commentaire