如何在 F# 中对异步方法进行单元测试?
How can I unit test an Asynchronous method in F#?
我有一个方法可以 returns 我正在尝试在 F# 中同步测试的任务。
这是方法,它是 C# 接口的实现:
member this.RunAsync(): System.Threading.Tasks.Task =
async{
this._settings.LogSettings |> Seq.iter(fun settings -> this.clearLogs(settings)) |> ignore
return ()
} |> Async.StartAsTask :> _
这是我的测试逻辑
Async.AwaitTask(logFileManager.RunAsync())|> Async.Ignore
// and I've tried
async {
logFileManager.RunAsync()
Assert.Pass()
} |> Async.RunSynchronously
测试运行,有 5 个项目,预期调用次数应为 5,但测试失败,随机调用次数介于 1 和 2 之间。
另一个实现的 C# 中的相同测试很简单:
[Test]
public async Task Should_do_something_in_an_asynchronous_method()
{
var unitUnderTest = GetService();
await unitUnderTest.RunAsync();
}
如何确保完成单元测试的任务?
如何编写与async
等效的测试方法?
查看 C# 代码中的 await
字。你认为它有什么作用?如果掉了怎么办?测试仍然有效吗?
答案是:"It makes the async call part of the surrounding async computation" 和 "No, it wouldn't"
不会,因为对 RunAsync
的调用将不再是周围计算的一部分,并且周围计算不会知道它必须 "wait"完成。
这正是您在 F# 代码中所做的:您只是调用函数并忘记它,而不是使其成为周围工作流的一部分。该功能关闭并开始自行工作,并且您的 async
工作流程朝着不同的方向发展。
在 F# 中,使嵌套调用成为周围流的一部分的方法是使用 let!
或 do!
关键字,这有点类似于 C# 中的 await
。像这样:
let f = async { ... }
let g = async {
let! x = f
printfn "f returned: %A" x
}
但在您的情况下,这不会立即起作用,因为 RunAsync
returns C# Task
,而不是 F# Async
。因此,您还需要从前者转换为后者。要进行转换,请使用 Async.AwaitTask
函数:
async {
do! logFileManager.RunAsync() |> Async.AwaitTask
Assert.Pass()
} |> Async.RunSynchronously
我有一个方法可以 returns 我正在尝试在 F# 中同步测试的任务。 这是方法,它是 C# 接口的实现:
member this.RunAsync(): System.Threading.Tasks.Task =
async{
this._settings.LogSettings |> Seq.iter(fun settings -> this.clearLogs(settings)) |> ignore
return ()
} |> Async.StartAsTask :> _
这是我的测试逻辑
Async.AwaitTask(logFileManager.RunAsync())|> Async.Ignore
// and I've tried
async {
logFileManager.RunAsync()
Assert.Pass()
} |> Async.RunSynchronously
测试运行,有 5 个项目,预期调用次数应为 5,但测试失败,随机调用次数介于 1 和 2 之间。
另一个实现的 C# 中的相同测试很简单:
[Test]
public async Task Should_do_something_in_an_asynchronous_method()
{
var unitUnderTest = GetService();
await unitUnderTest.RunAsync();
}
如何确保完成单元测试的任务?
如何编写与async
等效的测试方法?
查看 C# 代码中的 await
字。你认为它有什么作用?如果掉了怎么办?测试仍然有效吗?
答案是:"It makes the async call part of the surrounding async computation" 和 "No, it wouldn't"
不会,因为对 RunAsync
的调用将不再是周围计算的一部分,并且周围计算不会知道它必须 "wait"完成。
这正是您在 F# 代码中所做的:您只是调用函数并忘记它,而不是使其成为周围工作流的一部分。该功能关闭并开始自行工作,并且您的 async
工作流程朝着不同的方向发展。
在 F# 中,使嵌套调用成为周围流的一部分的方法是使用 let!
或 do!
关键字,这有点类似于 C# 中的 await
。像这样:
let f = async { ... }
let g = async {
let! x = f
printfn "f returned: %A" x
}
但在您的情况下,这不会立即起作用,因为 RunAsync
returns C# Task
,而不是 F# Async
。因此,您还需要从前者转换为后者。要进行转换,请使用 Async.AwaitTask
函数:
async {
do! logFileManager.RunAsync() |> Async.AwaitTask
Assert.Pass()
} |> Async.RunSynchronously