在寻找答案时,我发现了几个与我的情况不太匹配的问题 - 所以我会问一个新问题。
我正在为数据结构编写一些FsCheck测试,我想在我构建的数据结构的每个副本上检查20个不同的属性。到目前为止我所做的是为每个属性编写一个谓词,然后我已经列出了谓词列表,我将依次用List.forall
对它们进行调用,就像这样:
module PropertyChecks =
let ``Tail length plus tree length should equal vector length`` vec =
treeLength vec.root + Array.length vec.tail = vec.len
let ``The tail may only be empty iff the vector is empty`` vec =
(vec.len = 0) = (Array.length vec.tail = 0)
let ``The tail's length may not exceed tailMax`` vec =
Array.length vec.tail < tailMax
let ``If vec.len <= tailMax, all items are in tail and root is empty`` vec =
(vec.len > tailMax) || (Array.length vec.root = 0)
// And so on for about 15 more predicates
let allProperties =
[
``Tail length plus tree length should equal vector length``
``The tail may only be empty iff the vector is empty``
``The tail's length may not exceed tailMax``
``If vec.len <= tailMax, all items are in tail and root is empty``
]
let checkProperties vec =
allProperties |> List.forall (fun pred -> pred vec)
// Rest of my code omitted since it's not relevant to the question
我面临的问题是,我希望当一个属性因为我没有正确构建数据结构而失败时,两个或三个其他属性将同时失败。我想获取所有失败属性的列表,这意味着在checkProperties
中我想提取失败谓词的名称。我已经看到了#34的多个答案;你不能从你作为参数收到的任意F#函数中获得MethodInfo
,因为你永远不知道你是否得到了这个函数本身,或lambda,或匿名函数&#34;。但在这里,我不仅知道我有真正的功能,我知道他们的名字是什么。我可以轻松地将其名称复制并粘贴到字符串中,并使allProperties
成为(字符串,函数)元组的列表。但是我已经对复制和粘贴一次(将谓词放入该列表)感到不满意,而我宁愿不做两次。
制作(函数名称,函数)元组列表的更好解决方案是什么?我可以将allProperties
和checkProperties
移出PropertyChecks
模块,以便它只包含谓词,然后使用反射来遍历该模块吗?
我对整个.Net反射系统都很陌生,所以我很可能会遗漏一些明显的东西。如果我错过了,请随时指出明显的;我不会受到侮辱。
答案 0 :(得分:5)
运行FsCheck测试的最佳选择是将FsCheck与一些单元测试运行器一起使用。测试运行器负责查找所有属性,运行它们并在出现问题时打印漂亮的错误日志。
.NET中最常用的两个与FsCheck一起使用的测试运行器是xUnit和NUnit,FsCheck文档描述了如何使用它们:
在这两种情况下,您都使用[<Property>]
属性标记属性,测试运行器将使用它来查找它们并使用FsCheck为您运行它们。所以你需要这样的东西:
[<Property>]
let ``Tail length plus tree length should equal vector length`` vec =
treeLength vec.root + Array.length vec.tail = vec.len
[<Property>]
let ``The tail may only be empty iff the vector is empty`` vec =
(vec.len = 0) = (Array.length vec.tail = 0)
[<Property>]
let ``The tail's length may not exceed tailMax`` vec =
Array.length vec.tail < tailMax
[<Property>]
let ``If vec.len <= tailMax, all items are in tail and root is empty`` vec =
(vec.len > tailMax) || (Array.length vec.root = 0)
答案 1 :(得分:2)
这是一个hacky bash脚本,可能比反射更容易:
#!/bin/bash
echo "let pairs = [|";
cat t.fs | grep let | grep -o "\`\`[^\`]*\`\`" | tr -d \` | awk '{printf " (\"%s\",``%s``);\n", $0,$0}';
echo "|]"
给出:
let pairs = [|
("Tail length plus tree length should equal vector length",``Tail length plus tree length should equal vector length``);
("The tail may only be empty iff the vector is empty",``The tail may only be empty iff the vector is empty``);
("The tail's length may not exceed tailMax",``The tail's length may not exceed tailMax``);
("If vec.len <= tailMax, all items are in tail and root is empty",``If vec.len <= tailMax, all items are in tail and root is empty``);
|]