我正在尝试在 F# 中测试 MailboxProcessor。我想测试我给出的函数 f 在发布消息时是否实际执行。
原始代码使用 Xunit,但我制作了一个 fsx,可以使用 fsharpi 执行。
到目前为止,我正在这样做:
open System
open FSharp
open System.Threading
open System.Threading.Tasks
module MyModule =
type Agent<'a> = MailboxProcessor<'a>
let waitingFor timeOut (v:'a)=
let cts = new CancellationTokenSource(timeOut|> int)
let tcs = new TaskCompletionSource<'a>()
cts.Token.Register(fun (_) -> tcs.SetCanceled()) |> ignore
tcs ,Async.AwaitTask tcs.Task
type MyProcessor<'a>(f:'a->unit) =
let agent = Agent<'a>.Start(fun inbox ->
let rec loop() = async {
let! msg = inbox.Receive()
// some more complex should be used here
f msg
return! loop()
}
loop()
)
member this.Post(msg:'a) =
agent.Post msg
open MyModule
let myTest =
async {
let (tcs,waitingFor) = waitingFor 5000 0
let doThatWhenMessagepostedWithinAgent msg =
tcs.SetResult(msg)
let p = new MyProcessor<int>(doThatWhenMessagepostedWithinAgent)
p.Post 3
let! result = waitingFor
return result
}
myTest
|> Async.RunSynchronously
|> System.Console.WriteLine
//display 3 as expected
这段代码有效,但对我来说看起来不太好。
1) 在 f# 中 TaskCompletionSource 的使用是正常的,还是有一些专门的东西可以让我等待完成?
2)我在 waitingFor 函数中使用第二个参数来约束它,我知道我可以使用类型 MyType<'a>() 来做到这一点,还有其他选择吗?我宁愿不使用我觉得很麻烦的新 MyType。
3)除了这样做之外,还有其他选择来测试我的代理吗?到目前为止,我发现的唯一一篇关于该主题的文章是 2009 年的这篇博文http://www.markhneedham.com/blog/2009/05/30/f-testing-asynchronous-calls-to-mailboxprocessor/