捕获测试异常

时间:2017-10-29 12:44:49

标签: error-handling f#

我目前正在接受F#课程。我正在进行一个黑盒测试,我已经根据一项任务改写了一个函数。在这个测试期间,我应该通过输入错误的格式来测试函数(给需要int的函数一个字符串)我希望能够捕获异常并允许测试继续运行而不是退出。我怎样才能在f#中实现这一目标?

这是我到目前为止所尝试的:

#r "msort.dll"

let tests = [
    ("Sorted lists", [
        ([1;2;3;4;5;6;7;8;9;10], [1;2;3;4;5;6;7;8;9;10]);
        ([5000;6000;7000;8000;9000;10000;11000;12000;13000;14000], [5000;6000;7000;8000;9000;10000;11000;12000;13000;14000]);
        ([10;9;8;7;6;5;4;3;2;1], [1;2;3;4;5;6;7;8;9;10]);
        ([14000;13000;12000;11000;10000;9000;8000;7000;6000;5000], [5000;6000;7000;8000;9000;10000;11000;12000;13000;14000]);
    ])
    ("Wrong input formats", [
        ([], []);
        (["hello"], []);
    ])
]

printfn "Black-box testing of Merge Sort"
for i = 0 to tests.Length-1 do
    let (testName, testSet) = tests.[i]
    printfn "%d. %s" (i+1) testName
    for j = 0 to testSet.Length - 1 do
        try
            let (input, expected) = testSet.[j]
            let result = (msort.sort input)
            printfn "test %d - %b" (j+1) (result = expected)
        with
            | _ as ex -> printfn "error occured"

我原以为我可以用通配符捕获任何异常并在打印字符串后继续测试"出现错误"但程序只是关闭,但有例外:

error FS0001: This expression was expected to have type
    'int'    
but here has type
    'string'    

我正在测试的函数是重写的一个版本,用于使用模式匹配。这是函数的代码,编译成" msort.dll"

module msort

let rec merge (xs:int list) (ys:int list): int list =
  match xs with
    | []  -> ys                   // if xs is empty return ys
    | xs when ys = [] -> xs       // if ys is empty return xs
    | _   ->                      // if non of the above is true
      let x = List.head xs
      let y = List.head ys
      let xs = List.tail xs
      let ys = List.tail ys
      match x with
        | x when x <= y -> x :: merge xs (y::ys) // if x < y merge x
        | x when x > y -> y :: merge (x::xs) ys // else merge y
        | _ -> []                               // otherwise something is wrong, return empty array

let rec sort (xs:int list): int list =
  let sz = List.length xs
  if sz < 2 then xs           // if the length of sz is under 2 we cannot split and so we return xs
  else let n = sz / 2
       let ys = xs.[0..n-1]   // ys = the first half of the input array
       let zs = xs.[n..sz-1]  // zs = the second half of the input array
       in merge (sort ys) (sort zs) // call merge with each half

1 个答案:

答案 0 :(得分:3)

正如评论中所提到的,没有理由编写试图用无效类型的输入调用你的<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <application xmlns="http://ns.adobe.com/air/application/2.5"> <id>author.YourFileName</id> <versionNumber>1.0.0</versionNumber> <versionLabel/> <filename>YourFileName</filename> <description/> <!-- To localize the description, use the following format for the description element.<description><text xml:lang="en">English App description goes here</text><text xml:lang="fr">French App description goes here</text><text xml:lang="ja">Japanese App description goes here</text></description>--> <name>YourFileName</name> <!-- To localize the name, use the following format for the name element.<name><text xml:lang="en">English App name goes here</text><text xml:lang="fr">French App name goes here</text><text xml:lang="ja">Japanese App name goes here</text></name>--> <copyright/> <initialWindow> <content>YourFileName.swf</content> <systemChrome>standard</systemChrome> <transparent>false</transparent> <visible>true</visible> <fullScreen>true</fullScreen> <renderMode>gpu</renderMode> <autoOrients>true</autoOrients> </initialWindow> <icon> <image72x72>My_Assets/icons/YourFileName_icon_72.png</image72x72> <image48x48>My_Assets/icons/YourFileName_icon_48.png</image48x48> <image36x36>My_Assets/icons/YourFileName_icon_36.png</image36x36> </icon> <customUpdateUI>false</customUpdateUI> <allowBrowserInvocation>false</allowBrowserInvocation> <android> <manifestAdditions> <![CDATA[<manifest> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> </manifest>]]> </manifestAdditions> </android> </application> 函数的测试--F#编译器将静态检查这些情况并阻止它们,所以没有人如果它需要一个整数列表,可以用一个字符串列表调用该函数。

如果你有一个非静态类型安全的函数,那么你想要做的事情才会有意义。例如,如果您有sort在排序之前将所有输入转换为整数。您可以使用unsafeSort定义类似的函数,并通过System.Convert投射。

这非常难看且不安全,你永远不应该这样做,因为它违背了使用F#和静态类型的目的,但你可以在技术上做到这一点:

:?>

然后,您可以将测试的数据表示为对象,这将使您可以混合字符串和整数:

let unsafeSort list = 
  msort.sort [ for v in list -> System.Convert.ChangeType(v, typeof<int>) :?> int ]
  |> List.map box

使用以下操作运行测试将报告一次传递和一次错误:

let tests = [
    ("Sorted lists", [
        ([box 1;box 3;box 2], [box 1;box 2;box 3]);
    ])
    ("Wrong input formats", [
        (["hello"], []);
    ])
]

如前所述,这只是从技术方面回答你的问题 - 这是一个非常糟糕的主意。