次の非同期ワークフローをテストしたいと思います (NUnit+FsUnit を使用):
let foo = async {
failwith "oops"
return 42
}
私はそれのために次のテストを書きました:
let [<Test>] TestFoo () =
foo
|> Async.RunSynchronously
|> should equal 42
foo がスローされるため、単体テスト ランナーで次のスタック トレースを取得します。
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 と 2 つの選択肢の一致を取り除きながら、有用なスタック トレースを取得する方法はありますか? 非同期ワークフロー テストを構築するためのより良い方法はありますか?