2016-11-30 50 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