Reputation: 5858
I've got a method that returns a task I'm trying to test synchonously in F#. Here's the method, which is an implementation of a C# interface:
member this.RunAsync(): System.Threading.Tasks.Task =
async{
this._settings.LogSettings |> Seq.iter(fun settings -> this.clearLogs(settings)) |> ignore
return ()
} |> Async.StartAsTask :> _
Here's my test logic
Async.AwaitTask(logFileManager.RunAsync())|> Async.Ignore
// and I've tried
async {
logFileManager.RunAsync()
Assert.Pass()
} |> Async.RunSynchronously
The test runs, and with 5 items, the expected number of calls should be 5, but the test fails with a random number of calls between 1 and 2.
The same test in C# for another implementation is simply:
[Test]
public async Task Should_do_something_in_an_asynchronous_method()
{
var unitUnderTest = GetService();
await unitUnderTest.RunAsync();
}
How do I ensure the task is completed for the unit tests?
How do I write the equivalent test method with async
?
Upvotes: 1
Views: 434
Reputation: 80744
Take a look at the await
word in your C# code. What do you think it does? What if you dropped it? Would the test still work?
The answers are: "It makes the async call part of the surrounding async computation" and "No, it wouldn't"
It wouldn't, because the call to RunAsync
would no longer be a part of the surrounding computation, and the surrounding computation wouldn't know that it had to "wait" for it to complete.
And this is exactly what you're doing in your F# code: you're just calling the function and forgetting about it, not making it part of the surrounding workflow. The function goes off and starts working on its own, and your async
workflow goes off in a different direction.
In F#, the way to make nested calls a part of the surrounding flow is with let!
or do!
keywords, which are somewhat analogous to await
in C#. Like this:
let f = async { ... }
let g = async {
let! x = f
printfn "f returned: %A" x
}
But in your case this wouldn't work right away, because RunAsync
returns a C# Task
, not an F# Async
. So you need to also convert from the former to the latter. To do the conversion, use the Async.AwaitTask
function:
async {
do! logFileManager.RunAsync() |> Async.AwaitTask
Assert.Pass()
} |> Async.RunSynchronously
Upvotes: 5