2012-12-12 25 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測試運行器程序集加載/配置或相關問題的一個問題。 –