How to test the asynchronous methods in ms unit test leading to successful or failed unit tests
[<TestClass>]
type TestRequestDataClass () =
[<TestMethod>]
member this.TestRequestDataAsync() = async {
let! result = requestDataAsync()
match result with
| Ok result -> Assert.IsTrue(true)
| Error error -> Debug.WriteLine(error)
Assert.IsTrue(false)
}
I don't have MS Test to try this, but if you need to produce a method that returns non-generic Task (as opposed to generic Task<T>), then you can define the following helper:
open System.Threading.Tasks
let startAsActionTask f =
Async.StartAsTask f :> Task
The Async.StartAsTask always creates a generic Task<T>, but aside from that, it is pretty much the same as this helper. Then you can use the helper as follows:
[<TestMethod>]
member this.TestRequestDataAsync() = startAsActionTask <| async {
let! result = requestDataAsync()
match result with
| Ok result -> Assert.IsTrue(true)
| Error error -> Debug.WriteLine(error)
Assert.IsTrue(false)
}
Related
I want to check if an argument passed to the constructor of a type is valid.
I check it and raise an ArgumentException if not valid.
I want to create a test for this behavior. I want to use Assert.throws or preferably FSUnit instead of a try/with block.
#package "FsUnit#3.4.1"
#package "nunit#3.11.0"
open System
open FSUnit
type configuration = {aaa:int}
type Client(conf:configuration) =
do
if conf.aaa < 3 then raise (ArgumentException("aaa must be at least 3"))
member this.do_something() =
()
// TEST
// 1. does not "compile"
Assert.Throws<ArgumentException>(fun () -> Client(configuration) |> ignore)
// 2. does not work
//Assert.Throws<ArgumentException>( fun () ->
// let a = Client(configuration);
// a
// |> ignore)
// 3. does not work
(fun() -> Client(configuration)) |> ignore |> should throw typeof<ArgumentException>
// 4. OK but... bleah!
try
Client(configuration) |> ignore
Assert.Fail()
with
| :? ArgumentException -> Assert.Pass() |> ignore
| _ -> Assert.Fail()
Your first approach works fine for me - I just had to define configuration which is not included in your question but, presumably, is defined somewhere in your actual file. The following compiles and behaves as expected for me:
let configuration = { aaa = 1 }
Assert.Throws<ArgumentException>(fun () -> Client(configuration) |> ignore)
Your second code snippet does not work because it has ignore in the wrong place - you are ignoring the entire function (which contains the code that you want to test) and then you are passing unit to the assertion. The ignore call needs to be inside of the function so that it ignores the result of calling the constructor. The following works for me:
(fun() -> Client(configuration) |> ignore) |> should throw typeof<ArgumentException>
I'm on a Mac running F# using .NET Core 2.0.
I have a function that looks like this:
let rec evaluate(x: string) =
match x with
// ... cases
| _ -> failwith "illogical"
I'd like to write an Expecto test that validates that the exception is thrown as expected, something along the lines of:
// doesn't compile
testCase "non-logic" <| fun _ ->
Expect.throws (evaluate "Kirkspeak") "illogical"
The error is
This expression was expected to have type
'unit -> unit' but here has type 'char'
unit -> unit makes me this is analogous to Assert.Fail, which is not what I want.
Being somewhat new to F# and Expecto, I'm having trouble locating a working example of asserting that an exception is thrown as expected. Does anyone have one?
Expect.throws has the signature (unit -> unit) -> string -> unit so the function you want to test must be (unit -> unit) or be wrapped inside a function that is (unit -> unit).
let rec evaluate (x: string) : char =
match x with
// ... cases
| _ -> failwith "illogical"
The compiler error is telling you that the function you passed to Expect.throws does not have the right signature yet.
[<Tests>]
let tests = testList "samples" [
test "non-logic" {
// (evaluate "Kirkspeak") is (string -> char)
// but expecto wants (unit -> unit)
Expect.throws (evaluate "Kirkspeak") "illogical"
}
]
[<EntryPoint>]
let main argv =
Tests.runTestsInAssembly defaultConfig argv
One way to make it work is to change
Expect.throws (evaluate "Kirkspeak") "illogical"
to
// you could instead do (fun () -> ...)
// but one use of _ as a parameter is for when you don't care about the argument
// the compiler will infer _ to be unit
Expect.throws (fun _ -> evaluate "Kirkspeak" |> ignore) "illogical"
Now expecto is happy!
This answer was the way I thought through it. It is usually helpful to follow the type signatures.
EDIT: I saw your error message saying This expression was expected to have type 'unit -> unit' but here has type 'char' so I updated my answer to match it.
I have this code I'm running using Fable Elmish and Fable remoting to connect to a Suave server. I know that the server works because of postman and there are variations of this code that does call the server
let AuthUser model : Cmd<LogInMsg> =
let callServer = async {
let! result = server.RequestLogIn model.Credentials
return result
}
let result = callServer |> Async.RunSynchronously
match result with
| LogInFailed x -> Cmd.ofMsg (LogInMsg.LogInRejected x)
| UserLoggedIn x -> Cmd.ofMsg (LogInMsg.LogInSuccess x)
The callServer line in the let result fails with Object(...) is not a function, but I don't understand why. Any help would be appreciated.
According to Fable docs Async.RunSynchronously is not supported, though I'm not sure if that is causing your problem. Anyway you should structure your code so that you don't need to block asynchronous computations. In case of Elmish you can use Cmd.ofAsync to create a command out of an async that dispatches messages returned by the async when it completes.
let AuthUser model : Cmd<LogInMsg> =
let ofSuccess result =
match result with
| LogInFailed x -> LogInMsg.LogInRejected x
| UserLoggedIn x -> LogInMsg.LogInSuccess x
let ofError exn = (* Message representing failed HTTP request *)
Cmd.ofAsync server.RequestLogIn model.Credentials ofSuccess ofError
Hopefully this helps.
Right now I'm experimenting with F# computation expressions. General idea is to return control mechanism to drive actions executed after each step of recursive function call build from computation expression. Whole example can be seen here.
Using following example:
let rec loop () =
actor {
let! msg = m.Receive ()
match msg with
| "stop" -> return 0 // expected result: Return (0)
| "unhandled" -> unhandled // expected result: Unhandled
| x ->
mailbox.Sender() <! x
return! loop () // expected result: (Become(fun m -> loop ()))
}
loop ()
Unfortunately this ends with compile time error on unhandled: A custom operation may not be used in conjunction with 'use', 'try/with', 'try/finally', 'if/then/else' or 'match' operators within this computation expression.
Is it possible in any way to use custom operators inside match statements?
I'm not sure what the details of the actor computation are, but if Unhandled is a value of the underlying computation type, you can certainly produce it using return!
Without knowing the details, I think something like this should work:
match msg with
| "stop" -> return 0
| "unhandled" -> return! Unhandled
| x ->
mailbox.Sender() <! x
return! loop ()
Having
type Category(name : string, categoryType : CategoryType) =
do
if (name.Length = 0) then
invalidArg "name" "name is empty"
i'm trying to test this exception using FsUnit + xUnit:
[<Fact>]
let ``name should not be empty``() =
(fun () -> Category(String.Empty, CategoryType.Terminal)) |> should throw typeof<ArgumentException>
but when it runs I see XUnit.MatchException.
What i'm doing wrong?
Test source code
Category type source code
While I'm not an FsUnit expert, I think the MatchException type is expected, because FsUnit uses custom matchers, and the match doesn't succeed.
However, the test, as written, seems to be incorrect, because
(fun () -> Category(String.Empty, CategoryType.Terminal)
is a function with the signature unit -> Category, but you don't really care about the returned Category.
Instead, you can write it as
[<Fact>]
let ``name should not be empty``() =
(fun () -> Category(String.Empty, CategoryType.Terminal) |> ignore)
|> should throw typeof<ArgumentException>
Notice the added ignore keyword, which ignores the Category return value. This test passes, and fails if you remove the Guard Clause.