I am just learning F#, so i am trying a few things out(i do know could just use XUnit or something else)
I have the following assertion method, and the idea is that it should take an expected exception and the function that it expects to throw this exception, then execute the function and inside of the with test if the exception thrown is the same as the expected one.
let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested =
try
functionToBeTested
(false)
with
| :? Exception as someException when someException :? expected ->
printTestResultInMiddle (sprintf "Test: %s PASSED: Raised expected exception %A" testName expected) true
(true)
| _ ->
printTestResultInMiddle (sprintf "Test: %s FAILED: expected exception %A" testName expected) false
(false)
It gives me the error Unexpected symbol '(' in pattern matching. Expected '->' or other token. in the line where i try to call a print method. Shouldn't i be able to treat this try ... with as a
match ... with
??
And another question, could I do this a lot easier or?
First,
You're trying to use the type query operator :? with value expected of type 'a. This operator cannot be used with values, only with types:
let x = box 5
let a = x :? int // true
let b = x :? string // false
let y = 10
let c = x :? y // error: type 'y' is not defined
In your example (working with exceptions), this would look like this:
someException :? InvalidOperationException
Or, if you want to compare with type parameter:
someException :? 'a
Second,
why do you even give name to someException if all you want to do is just compare its type? That's exactly what the with | :? clause is doing to begin with:
try
...
with
| :? 'a ->
...
And then, you don't actually need the value expected, since all you want to probe is the type. So you can just declare the generic parameter and do away with the regular one:
let assertException<'a> (testName : string) functionToBeTested =
...
And finally,
your functionToBeTested is not actually a function, since you're not calling it. If you want to verify that it throws a specific exception during execution, you need to actually make the call:
functionToBeTested()
Putting it all together:
let assertException<'a when :> exn> (testName : string) functionToBeTested =
try
functionToBeTested()
(false)
with
| :? 'a ->
printTestResultInMiddle (sprintf "Test: %s PASSED: Raised expected exception %A" testName typeof<'a>.Name) true
(true)
| _ ->
printTestResultInMiddle (sprintf "Test: %s FAILED: expected exception %A" testName typeof<'a>.Name) false
(false)
Apparently you need to put parentheses around the when expression here. And you need to be checking against the type of expected, which is 'a. The following should compile (it worked for me when I replaced your printTestResultInMiddle calls with printfn calls):
let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested =
try
functionToBeTested
(false)
with
| :? Exception as someException when (someException :? 'a) ->
printTestResultInMiddle (sprintf "Test: %s PASSED: Raised expected exception %A" testName expected) true
(true)
| _ ->
printTestResultInMiddle (sprintf "Test: %s FAILED: expected exception %A" testName expected) false
(false)
However, that give a warning on the :? Exception as someException expression:
warning FS0067: This type test or downcast will always hold
That's because according to the try ... with documentation, a bare identifier is equivalent to :? System.Exception as <identifier>. So you can simplify your function down to:
let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested =
try
functionToBeTested
(false)
with
| someException when (someException :? 'a) ->
printTestResultInMiddle (sprintf "Test: %s PASSED: Raised expected exception %A" testName expected) true
(true)
| _ ->
printTestResultInMiddle (sprintf "Test: %s FAILED: expected exception %A" testName expected) false
(false)
But actually, it's even simpler to do it this way:
let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested =
try
functionToBeTested
(false)
with
| :? 'a ->
printTestResultInMiddle (sprintf "Test: %s PASSED: Raised expected exception %A" testName expected) true
(true)
| _ ->
printTestResultInMiddle (sprintf "Test: %s FAILED: expected exception %A" testName expected) false
(false)
That also compiles when I try it in F# Interactive, though I haven't actually tested it. I do notice that your functionToBeTested in the try expression should probably be a function call (i.e., functionToBeTested (). And you don't need those parentheses around the (true) and (false) expressions either.
So one more iteration of your code, as simple as I can make it without changing its semantics (and note that I have changed its semantics just a little bit with functionToBeTested ()) would be:
let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested =
try
functionToBeTested ()
false
with
| :? 'a ->
printTestResultInMiddle (sprintf "Test: %s PASSED: Raised expected exception %A" testName expected) true
true
| _ ->
printTestResultInMiddle (sprintf "Test: %s FAILED: expected exception %A" testName expected) false
false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With