9

How do I write an async test method in F#?

I'm referencing the following code:

[TestMethod]
public async Task CorrectlyFailingTest()
{
  await SystemUnderTest.FailAsync();
}

This is my failed attempt:

[<Test>]
let ``Correctly failing test``() = async {

        SystemUnderTest.FailAsync() | Async.RunSynchronously
    }
3
  • Is this using NUnit? Commented Sep 14, 2017 at 20:51
  • Yes. I'm using NUnit. Commented Sep 14, 2017 at 20:56
  • 1
    Have you tried simply removing the async { } and making the test synchronous? I.e., SystemUnderTest.FailAsync() |> Async.AwaitIAsyncResult |> Async.RunSynchronously, and that's it. Or if a synchronous test would not fit your requirements, and the test has to be asynchronous, then I'd recommend looking into Expecto, where asynchronous tests are the norm rather than the exception. Commented Sep 15, 2017 at 1:48

4 Answers 4

6

So after a bit of research, it turns out that this is more difficult than it ought to be. https://github.com/nunit/nunit/issues/34

That being said a workaround was mentioned. This seems kinda lame but, it looks like declaring a task delegate outside as a member and leveraging it is a viable work around.

The examples mentioned in the thread:

open System.Threading.Tasks
open System.Runtime.CompilerServices

let toTask computation : Task = Async.StartAsTask computation :> _

[<Test>]
[<AsyncStateMachine(typeof<Task>)>]
member x.``Test``() = toTask <| async {
    do! asyncStuff()
}

And

open System.Threading.Tasks
open NUnit.Framework

let toAsyncTestDelegate computation = 
    new AsyncTestDelegate(fun () -> Async.StartAsTask computation :> Task)

[<Test>]
member x.``TestWithNUnit``() = 
    Assert.ThrowsAsync<InvalidOperationException>(asyncStuff 123 |> toAsyncTestDelegate)
    |> ignore

[<Test>]
member x.``TestWithFsUnit``() = 
    asyncStuff 123 
    |> toAsyncTestDelegate
    |> should throw typeof<InvalidOperationException>

XUnit had a similar problem and did come up with a solution: https://github.com/xunit/xunit/issues/955

So you should be able to do this in xunit

[<Fact>]
let ``my async test``() =
  async {
    let! x = someAsyncCall()
    AssertOnX
  }

Sorry if this is not the most satisfying answer.

Sign up to request clarification or add additional context in comments.

4 Comments

I tried the XUnit example you provided and got the following error:
Error FS0001 This expression was expected to have type 'Async<'a>' but here has type 'System.Threading.Tasks.Task<System.Web.Mvc.ActionResult>'
I applied your XUnit example with: do! Async.AwaitTask( someAsyncCall())|> Async.Ignore
4
open Xunit

[<Fact>]
let ``my async test``() =
  async {
    do! Async.AwaitTask(someAsyncCall())|> Async.Ignore
    AssertOnX
  }

Comments

0

I asked https://github.com/fsprojects/FsUnit/issues/153 because I think that it is a responsibility of the F# unit testing framework to provide a right binding. Meanwhile, this looks the best for me.

    open System.Threading.Tasks

    let runAsyncTest async = async |> Async.StartImmediateAsTask :> Task

    [<Test>]
    let ``Some test`` () = runAsyncTest <| async {
    }

Comments

0

This is an old question but now can use the task builder from the Ply package for testing C# async methods in Xunit like so:

    open FSharp.Control.Tasks
    open System.Threading
    open Xunit
    
    let ``Test some Task returning async method`` () =
        task {
            let! actual = MyType.GetSomethingAsync()
            Assert.Equal(expected, actual)
            
            return ()
        }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.