2012-12-12 55 views
6

我想在F#中编写一些NUnit测试,并且无法将函数传递给ThrowsConstraint。下面是蒸馏(非)工作样品。如何将函数传递给NUnit引发约束?

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

这将编译得很好,但我从NUnit的测试运行如下:

FsTest.Tests.Example.foo: 
System.ArgumentException : The actual value must be a TestDelegate but was [email protected] 
Parameter name: actual 

虽然我可以在使用ExpectedException属性来解决这个问题,我的问题是什么是正确的在这种情况下使用F#函数的方法?

回答

7

为了让您的原始代码段能够正常工作,您只需修复f即可得到符合TestDelegate的签名,即unit -> unit。刚丢弃的File.GetAttributes返回值:

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

F#编译器并没有在原来的代码BARF因为只是另一件NUnit的超载Assert.That(actual: obj, expression: Constraints.IResolveConstraint)存在。

由于Assert.That具有十分广阔的用法我会坚持测试预计例外更具体的断言的形式,例如:

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

其中F#编译器将能够静态发现你的函数的签名错误。

+0

非常感谢您的解释。 –

+0

不错,它的好解决方案,因为在F#(VS 2010)属性方法不适合我(我试图用ExpectedException属性标记测试方法,它根本不工作) 谢谢! – Roboblob

4

恕我直言,你可以通过在NUnit之上使用Unquote来节省自己的一些痛苦。那么你的说法是一样简单

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

NUnit的的大套房断言重载用有时会出现意想不到的运行时行为的目的是弥补C#的相对缺乏表现相比,F#。

的On-the-其他手,因为F#是已经配备的功能,如优雅的表达断言结构相比,引文结束旨在利用其固有的特点,只需三个简单的断言运营商:testraisesraisesWith

+0

+1提醒Unquote。 –

+0

这非常有趣,因为我的第一件事是尝试了。不幸的是,NUnit和unquote的组合并不适合我,所以我回到了NUnit断言。我已经总结了NUnit的问题,并将其作为[不同的问题]发布(http://stackoverflow.com/questions/13846561/missingmethodexception-when-using-unquote-asserts),你的帮助会不胜感激。 –

+0

对不起@SergeBelov,这是不幸的!我为您的新问题添加了评论。我相信你所遇到的问题不在于Unquote本身,而是NUnit测试运行器程序集加载/配置或相关问题的一个问题。 –