使用xUnit.net的Task支持测试F#异步工作流

Rub*_*ink 6 workflow f# unit-testing asynchronous xunit.net

我在xUnit 1.9中编写F#代码和测试.

对于普通同步的东西,我只是返回unit,一切都很好; 但现在,我正在将同步内部迁移为async工作流程.

换句话说,Async当我重构系统时,我的简单AAA正在将明确的用法推入其中:

let [<Fact>] ``Can consume using NEventStore InMemory`` () = 
    let store = NesGateway.createInMemory ()

    let finalDirection = playCircuit store |> Async.RunSynchronously // <----- YUCK

    test <@ CounterClockWise = finalDirection @> 
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我想让测试的主体成为async.但是,据我所知,xUnit.net只管理返回Task-derived类型的方法,因此我需要一种安全的方法让我的async测试体适当地包装,以便xUnit.net的跑步者选择它并适当地处理它.

表达上述测试的最佳方式是什么?

Rub*_*ink 8

作为xUnit 2.2 Beta 3的一部分,@ Brad Wilson已经做了必要的工作,使其直接在本地工作.因此,现在可以简单地写:

let [<Fact>] ``Can consume NEventStore InMemory`` () = async {
    let store = NesGateway.createInMemory ()

    let! finalDirection = playCircuit store

    test <@ CounterClockWise = finalDirection @> }
Run Code Online (Sandbox Code Playgroud)


Rub*_*ink 5

不幸的是(据我所知[虽然没有说很多,因此问题]),最干净的是Async.StartAsTask <| async如此使用苹果化:

let [<Fact>] ``Can consume NEventStore InMemory`` () = Async.StartAsTask <| async {
    let store = NesGateway.createInMemory ()

    let! finalDirection = playCircuit store

    test <@ CounterClockWise = finalDirection @> }
Run Code Online (Sandbox Code Playgroud)

或者,为了更安全一点([Fact]如果返回类型不是[派生自],则异步不会被xUnit.net识别为同步Task)和[可以说]清洁度(读取更好):

// Ensure we match the return type xUnit.net is looking for
let toFact computation : Task = Async.StartAsTask computation :> _

let [<Fact>] ``Can play a circuit using GES``() = toFact <| async { 
    use! store = createStore()
    let! finalDirection = playCircuit store
    CounterClockWise =! finalDirection }
Run Code Online (Sandbox Code Playgroud)