How to assert an exception is expected

1.2k Views Asked by At

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?

1

There are 1 best solutions below

6
On BEST ANSWER

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!

expecto says the test asserting an exception throws passes

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.