避免在守则中明确写测试名称(作为指示)的一种办法是使用引文。 您不但没有制定一份职能清单和说明清单,反而可以编制一份“援引”职能价值清单。 然后,你可以写法,处理报价,并给你所需要的一切。
我假定,你的测试大致如下(因此而计算单位和退还一定价值的职能)。 清单如下:
let test_a () = Some 32
let test_b () = None
let tests = [ <@ test_a @>; <@ test_b @> ]
然后,你可以撰写这样的法典,以获得有关测试的信息:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
let getInfo (e:Expr<unit -> R>) = //
match e.Raw with
// This expects that the quotation contains a reference to a global
// function (in some module) that takes unit as the parameter
| Lambda(a, Call(_, m, _)) ->
// Return a tuple containing a name of the test (string) and
// a function that invokes it (note that the invocation will be
// a bit slow as we use reflection here)
m.Name, (fun () -> m.Invoke(null, [| |]) :?> R) // (*)
// Ohter quotations will cause an exception
| _ -> failwith "unexpected quotation"
下面是你将如何利用:
let e = <@ test_a @>
let s, f = getInfo e // gives string * (unit -> int option)
// Your original code could be written like this:
tests |> List.map getInfo |> List.tryPick (fun (title, test) ->
test () |> Option.map (fun s -> (title, s)))
或者,您可以修改<代码>(*),以产生一种功能,将测试的名称和结果重新命名,从而不再需要<代码>。 备选案文:
// An alternative version of the marked line in the getInfo function
(fun () -> m.Name, m.Invoke(null, [| |]) :?> R) // (*)
// Then you can write just:
tests |> List.map getInfo |> List.tryPick (fun test -> test())