Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass a function to NUnit Throws Constraint?

Tags:

interop

f#

nunit

I'm trying to write some NUnit tests in F# and having trouble passing a function to the ThrowsConstraint. A distilled (non)working sample is below.

open System.IO
open NUnit.Framework

[<TestFixture>]
module Example =

    [<Test>]
    let foo() = 
        let f = fun () -> File.GetAttributes("non-existing.file")
        Assert.That(f, Throws.TypeOf<FileNotFoundException>())

This compiles just fine but I get the following from the NUnit test runner:

FsTest.Tests.Example.foo:
System.ArgumentException : The actual value must be a TestDelegate but was f@11
Parameter name: actual

While I'm able to work around the problem using ExpectedException attribute, my question is what is the correct way of using an F# function in this situation?

like image 577
Serge Belov Avatar asked Dec 12 '12 04:12

Serge Belov


People also ask

What is assert throws?

Assert. Throws returns the exception that's thrown which lets you assert on the exception. var ex = Assert.

What is the difference between assert throws and assert catch?

Catch is similar to Assert. Throws but will pass for an exception that is derived from the one specified. So use Assert. Catch if an exception that derives from the specified exception is valid (meaning that it too would be caught in an equivalent catch block).

How do I catch exceptions in Nunit?

Throws( Is. InstanceOf<ApplicationException>(), code ); // Allow both ApplicationException and any derived type Assert. Catch<ApplicationException>( code ); // Allow any kind of exception Assert. Catch( code );

What is assert that in Nunit?

Asserts that a condition is true. If the condition is false the method throws an AssertionException. That(Boolean, String) Asserts that a condition is true. If the condition is false the method throws an AssertionException.


2 Answers

All you need to do in order for your original snippet to work is fixing f to have signature conformant to TestDelegate, which is unit -> unit. Just discard return value of File.GetAttributes:

let f = fun () -> File.GetAttributes("non-existing.file") |> ignore

F# compiler did not barf at your original code because just another fitting NUnit overload Assert.That(actual: obj, expression: Constraints.IResolveConstraint) exists.

As Assert.That has very broad usage I'd stick for testing expected exceptions to more specific assert form, for example:

[<Test>]
let foo() =
    Assert.Throws<FileNotFoundException>
        (fun () -> File.GetAttributes("non-existing.file")|> ignore)
    |> ignore

where F# compiler would be able statically spot the wrong signature of your function.

like image 63
Gene Belitski Avatar answered Dec 11 '22 09:12

Gene Belitski


IMHO, you could save yourself some pain by using Unquote on top of NUnit. Then your assertion would be as simple as

[<Test>]
let foo() = 
    raises<FileNotFoundException> <@ File.GetAttributes("non-existing.file") @>

NUnit's large suite of assertion overloads with sometimes unexpected runtime behavior are designed to compensate for C#'s relative lack of expressiveness compared to F#.

On-the-other-hand, because F# is already equipped with features such as structural comparison for elegantly expressing assertions, Unquote is designed to exploit its native features with just three simple assertion operators: test, raises, and raisesWith.

like image 31
Stephen Swensen Avatar answered Dec 11 '22 09:12

Stephen Swensen