Search code examples
exceptiontestingf#assert

Trying to put together a few assertion functions and i cannot get a try with to work


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?


Solution

  • 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)