2016-11-30 37 views
3

我剛學F#一試,所以我嘗試一些東西出來(我知道可以只使用的xUnit或別的東西)試圖拼湊幾個斷言功能,我不能讓一起工作

我有下面的斷言方法,其思想是它應該採用預期的異常和它期望拋出此異常的函數,然後在with test中執行函數和內部,如果拋出的異常與預期異常相同。

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) 

它給我錯誤Unexpected symbol '(' in pattern matching. Expected '->' or other token.在我嘗試調用打印方法的行中。我不應該能夠把這個try ... with當作

match ... with 

??

而另一個問題,我可以做更容易或?

+3

*「我能做到這一點輕鬆了許多或?「*是的,您可以使用[Unquote](http://www.swensensoftware.com/unquote),這非常棒! –

回答

5

首先,
您正試圖使用​​類型'a的值爲expected的類型查詢運算符:?。該運營商不能與值,只能用於類型:

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 

在您的例子(有例外的工作),這應該是這樣的:

someException :? InvalidOperationException 

或者,如果你想與類型比較參數:

someException :? 'a 


你爲什麼連給的名字someException如果你想要做的只是比較它的類型?這正是該with | :?子句做開始與:

try 
    ... 
with 
| :? 'a -> 
    ... 

然後,你實際上並不需要的價值expected,因爲所有你想要探頭類型。所以,你可以聲明泛型參數,並與常規的一個做掉:

let assertException<'a> (testName : string) functionToBeTested = 
    ... 

最後,
functionToBeTested實際上不是一個功能,因爲你不調用它。如果你想驗證它的執行過程中拋出一個特定的異常,實際上你需要撥打電話:

 functionToBeTested() 

全部放在一起:

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) 
+1

'printTestResultInMiddle'調用需要'expected';也''a'缺少一個約束'<'a'當一個:> exn>' – Sehnsucht

+0

謝謝,添加了約束。只有爲了打印出類型名稱才需要'expected'。 –

3

顯然你需要在這裏把when表達式括起來。而且您需要檢查類型expected,這是'a。以下應編譯(它的工作對我來說,當我換成你printTestResultInMiddle電話與printfn電話):

let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested = 
    try 
     functionToBeTested 
     (false) 
    with 
    | :? Exception as someException when (someException :? 'a) -> 
      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) 

然而,這給在:? Exception as someException表達一個警告:

警告FS0067:此型式試驗或downcast將始終保持

這是因爲根據try ... with documentation,裸露標識符相當於:? System.Exception as <identifier>。所以,你可以簡化你的函數到:

let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested = 
    try 
     functionToBeTested 
     (false) 
    with 
    | someException when (someException :? 'a) -> 
      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) 

但實際上,它做這種方式的更簡單:

let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested = 
    try 
     functionToBeTested 
     (false) 
    with 
    | :? 'a -> 
      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) 

這也編譯時,我嘗試在F#互動,雖然我的天堂」實際上測試了它。我注意到你在try表達functionToBeTested也許應該是一個函數調用(即functionToBeTested()。而且你也不需要圍繞(true)(false)表達這些括號無論是。

所以,你的代碼的一個更迭代,如簡單,我可以把它在不改變其語義(請注意,我改變了它的語義只是functionToBeTested()一點點)將是:

let assertException (testName : string) (expected : 'a when 'a :> Exception) functionToBeTested = 
    try 
     functionToBeTested() 
     false 
    with 
    | :? 'a -> 
      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