【发布时间】:2013-08-12 16:43:32
【问题描述】:
我想测试以下异步工作流程(使用 NUnit+FsUnit):
let foo = async {
failwith "oops"
return 42
}
我为它写了以下测试:
let [<Test>] TestFoo () =
foo
|> Async.RunSynchronously
|> should equal 42
由于 foo throws 我在单元测试运行器中得到以下堆栈跟踪:
System.Exception : oops
at Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronously(CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout)
at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously(FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
at ExplorationTests.TestFoo() in ExplorationTests.fs: line 76
不幸的是,堆栈跟踪没有告诉我异常是在哪里引发的。它在 RunSynchronously 处停止。
我听说 Async.Catch 神奇地恢复了堆栈跟踪,所以我调整了我的测试:
let [<Test>] TestFooWithBetterStacktrace () =
foo
|> Async.Catch
|> Async.RunSynchronously
|> fun x -> match x with
| Choice1Of2 x -> x |> should equal 42
| Choice2Of2 ex -> raise (new System.Exception(null, ex))
现在这很难看,但至少它产生了有用的堆栈跟踪:
System.Exception : Exception of type 'System.Exception' was thrown.
----> System.Exception : oops
at Microsoft.FSharp.Core.Operators.Raise(Exception exn)
at ExplorationTests.TestFooWithBetterStacktrace() in ExplorationTests.fs: line 86
--Exception
at Microsoft.FSharp.Core.Operators.FailWith(String message)
at ExplorationTests.foo@71.Invoke(Unit unitVar) in ExplorationTests.fs: line 71
at Microsoft.FSharp.Control.AsyncBuilderImpl.callA@769.Invoke(AsyncParams`1 args)
这次堆栈跟踪准确地显示了错误发生的位置:ExplorationTests.foo@line 71
有没有办法摆脱 Async.Catch 和两个选项之间的匹配,同时仍然获得有用的堆栈跟踪?有没有更好的方法来构建异步工作流测试?
【问题讨论】:
-
我遇到了同样的问题,Async.Catch 是我能找到的唯一解决方法
-
我已向 Don Syme 发送电子邮件,他认为这是 .NET 的基本限制,而
Async.Catch是唯一的选择。 -
@JohnPalmer 听起来像是对我的回答
标签: unit-testing f# nunit async-workflow