Asserting exception message using FsUnit.Xunit - f#

I'm trying to assert a certain exception type and message using FsUnit.Xunit.
There is some throwWithMessage function that comes with FsUnit. However, when using it instead of the throw function fsc emits the following errors:
C:\src\foo.fs(29,12): error FS0001: This expression was expected to have type '(unit -> unit) -> 'a' but here has type 'unit'
C:\src\foo.fs(29,19): error FS0001: The type ''a -> NHamcrest.Core.CustomMatcher<obj>' is not compatible with the type 'NHamcrest.IMatcher<obj>'
C:\src\foo.fs(29,12): error FS0001: This expression was expected to have type '(unit -> unit) -> 'a' but here has type 'unit'
This is the test that won't compile:
[<Fact>]
let ``Some test`` () =
(fun () -> This.Throws("a", 10) |> ignore)
|> should throwWithMessage "Some message" typeof<ArgumentException> //This is line 29
//^ column index 12 is here
//^ here is column index 19
I'm not sure what's wrong here.
Versions:
FsUnit/FsUnit.Xunit 3.1.0
NHamcrest (as referenced by FsUnit.Xunit) 2.0.1
Xunit 2.3.1

Welp, I missed some brackets. This works:
[<Fact>]
let ``Some test`` () =
(fun () -> This.Throws("a", 10) |> ignore)
|> should (throwWithMessage "Some message") typeof<ArgumentException>

Related

Parameterized exception type [duplicate]

How can I define an exception like the following?
exception CustomExn<'TMessage> of 'TMessage list
Maybe you can just inherit from System.Exception?
type CustomExn<'TMessage> (message:'TMessage list) =
inherit System.Exception ()
let test =
try
raise (CustomExn["string"] )
with
| :? CustomExn<string> -> "CustomExn of string"
| :? CustomExn<int> -> "CustomExn of int"
| _ -> "Everything else"
Not sure it is possible with F# Exception Definitions according to specs (page 164-165)
This one also NOT A GOOD SOLUTION because try with will only catch ExceptionList<string> in this case so there is no good way to make it generic
type ExceptionList<'a>(msgList: 'a list) =
inherit Exception()
member __.MessageList = msgList
let mock() =
raise <| ExceptionList(["failed"])
try
mock() //raises ExceptionList<string>
with
//this catch block won't fire, because it is not generic, it is ExceptionList<obj>
| :? ExceptionList<_> as exnList ->
exnList.MessageList
|> List.iter (printfn "%A")
The better way though: Result<'a,'b list>:
let mock'() =
if DateTime.Now.Ticks % 2L = 0L
then Ok()
else Error(["failed"])
let result = mock'()
match result with
| Ok _ -> printfn "Ok!"
| Error (msgList) ->
msgList
|> List.iter (printfn "%A")
Added There is a workaround with type loss:
type ExceptionList(msgList: obj list) =
inherit Exception()
member __.MessageList = msgList
// Here is F# exception definition
exception CustomException of ExceptionList
let failwithMany msgs =
raise <| CustomException (ExceptionList(msgs))
let mock() =
//zero type checking here
failwithMany[1;2;"a";[];"failed"]
try
mock()
with
// exnList is list of objects
| CustomException exnList ->
exnList.MessageList
|> List.iter (printfn "%A")

What is the second parameter of Unquote raisesWith for?

in the unquote userguide there is an example given, which i don't understand:
// raisesWith : Expr -> (#exn -> Expr<bool>) -> unit
raisesWith<System.NullReferenceException> <# ("s":string).Length #> (fun e -> <# e.ToString() = null #>)
You can give a short explanation and another example ?
You can assert on the error, as in the following example
raisesWith<DivideByZeroException> <# 1/0 #> (fun e -> <# e.Message = "Attempted to divide by zero." #>)

FsUnit assert exception message

How to assert on exception message in FsUnit? Something like this from NUnit:
[<Test>]
let ShouldThrowExceptionAndLog() =
Assert.That
((fun () -> Calculator.Calculate "-1"),
Throws.Exception.With.Property("Message").EqualTo("Negatives not allowed: -1"))
EDIT: I don't care about the exception itself, I'd like to test the exception MESSAGE.
AFAIK there is no out-of-the-box matcher to do what you want, but it's easy enough to create one yourself:
open NHamcrest
let throwAnyWithMessage m =
CustomMatcher<obj>(m,
fun f -> match f with
| :? (unit -> unit) as testFunc ->
try
testFunc()
false
with
| ex -> ex.Message = m
| _ -> false )
usage:
(fun () -> raise <| Exception("Foo") |> ignore) |> should throwAnyWithMessage "Foo" // pass
(fun () -> raise <| Exception("Bar") |> ignore) |> should throwAnyWithMessage "Foo" // fail

Type mismatch compilation error with tuple

The Tour of f# has a sample similar to this code:
let swap_tuple (a, b) = (b, a)
let result = swap_tuple ("one", "two")
printfn "%A" result // prints ("two", "one")
So the code above work. But why does this code:
let swap_tuple (a, b) = (b, a)
printfn "%A" swap_tuple ("one", "two")
throws this compilation error:
error FS0001:
Type mismatch. Expecting a 'a -> 'b -> 'c but given a 'a -> unit
The type ''a -> 'b' does not match the type 'unit'
What is wrong in the second version?
In your second version, your format string has just the one format specifier, but the printfn statement has been suppplied with two. You need to use () to group together swap_tuple with its arguments into a single argument.
let swap_tuple (a, b) = (b, a)
printfn "%A" (swap_tuple ("one", "two") )
As an alternative to Jimmy's answer, you could also use the pipeline operators:
printfn "%A" <| swap_tuple ("one", "two")
or
("one", "two")
|> swap_tuple
|> printfn "%A"

List.map fsi is telling ok, but can't build

Why this piece of code is working on my fsi, but can't build the project? I am using vs2010 and F# 2.0 ...Any ideas that I am missing something?
let arg = [#"C:\Temp\bin"; #"C:\temp\xml"]
arg|> List.map(fun (s) -> printfn "%s" s)
getting the error telling that it was expecting int, how?
Error 1
Type mismatch. Expecting a string list -> int but given a string list -> 'a list
The type 'int' does not match the type ''a list'
C:\Users\Ebru\Documents\Visual Studio 2010\Projects\WinFind\WinFind\Program.fs
I'm guessing you actually wrote
[<EntryPoint>]
let Main(args) =
let arg = [#"C:\Temp\bin"; #"C:\temp\xml"]
arg|> List.map(fun (s) -> printfn "%s" s)
and an EntryPoint method (e.g. Main()) must return an int.
this snippet compiles on my machine, but the mapping seems weird. I think you really what to do this:
let arg = [#"C:\Temp\bin"; #"C:\temp\xml"]
arg|> List.iter (fun s -> printfn "%s" s)
which is the same as:
let arg = [#"C:\Temp\bin"; #"C:\temp\xml"]
arg|> List.iter (printfn "%s")
Regards,
forki

Resources