10

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?

Serge Belov
  • 5,633
  • 1
  • 31
  • 40

2 Answers2

10

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.

Gene Belitski
  • 10,270
  • 1
  • 34
  • 54
  • Nice, its good solution, because in F# (VS 2010) attribute approach was not working for me (i tried marking the test method with ExpectedException attribute and it did not work at all) Thanks! – Roboblob Apr 10 '13 at 09:10
4

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.

Stephen Swensen
  • 22,107
  • 9
  • 81
  • 136
  • It's quite interesting because unquote was the first thing I've tried. Unfortunately the combination of NUnit and unquote didn't quite work for me so I got back to NUnit asserts. I've summarized the issue I had with NUnit and unquote and posted it as a [different question](http://stackoverflow.com/questions/13846561/missingmethodexception-when-using-unquote-asserts), your help with that would be appreciated. – Serge Belov Dec 12 '12 at 18:53
  • Sorry @SergeBelov, that's unfortunate! I added a comment to your new question. I believe the issue you are having is not with Unquote per se, but is rather an issue with the NUnit test runner assembly loading / configuration or something along those lines. – Stephen Swensen Dec 12 '12 at 19:13
  • @StephenSwensen No worries at all and thanks for your help. Apart from that NUnit question, what would you recommend as a test runner for Unqoute? I like the unquote approach a lot and do not have a strict requirement to use NUnit. – Serge Belov Dec 12 '12 at 19:21
  • I like TestDriven.NET: http://www.testdriven.net/. It integrates with Visual Studio, is very fast, and has always worked issue free for me with F# + Unquote + NUnit or xUnit.net. It is free for open source projects, but cost money for commercial projects. If that's an issue, I think the NUnit GUI test runner should be fine once we get past whatever issue it is having (I've had it working before, but an older version for .NET 4.0). Also, xUnit.net is a fine alternative to NUnit, and is what Unquote uses for its own suite of automated tests. – Stephen Swensen Dec 12 '12 at 19:30