概括
是否有任何事件可以在每个属性案例之前运行,以便我可以为属性的每次运行运行设置和拆卸?
完整版本
我希望能够通过属性测试成对的行为,例如“我总是可以获取书面记录”或“readAllLines 的输出等于 writeAllLines 的输入”。我还希望该属性不关心操作集是如何实现的(即是否需要清理任何资源)。
每次运行该属性应
- 独立于其他运行
- 在此单次运行中维护操作调用之间的状态
- 不知道操作如何保持状态
- 不是资源泄漏
我正在使用 FsCheck 和 Expecto。示例将在 Expecto 中,但问题并非特定于框架。
使用基于示例的测试编写这种设置和拆卸非常容易。它们采用可预测的参数集,因此我可以在添加事件前后的包装器中运行它们。
let testWithEnv setup cleanup name test =
let testWrap () =
let (api, env) = setup ()
test api
cleanup env
testCase name testWrap
属性测试不能做同样的事情。他们有未知数量的参数,这些参数将主要填充随机数据。
我可以很容易地应用这组配对行为,但是任何创建的资源(如流)都不会被处理。
let testPropertyWithEnv setup cleanup name test =
let testWrap () =
let (api, env) = setup () // this is actually run once, but immutable so the individual runs don't leak state
test api // have to return this to pass along unapplied parameters
testProperty name testWrap
我调查过
跑步者活动查看如何运行 FsCheck 测试最接近的钩子似乎是
OnStartFixture
每个测试类只运行一次OnArguments
在每次通过后运行,并且可能会运行清理
还有一些实验性的基于模型的测试功能可以工作。但是,考虑到我只关心操作的外部一致性,这似乎真的很重。我不想访问支持状态。
放弃和内联我总能写
testProperty "name" (fun arg1 arg2 ->
let (api,env) = setup ()
//test code here
cleanup env
)
但我想避免每个属性中的样板和支持状态的暴露。
一次性用品一次性对象也没有解决缺少设置挂钩的问题。
更多动手操作的运行循环我研究了在包装器中运行属性测试的方法,但最小的运行器Check.one
是针对单个属性的,在属性的运行之间没有挂钩。
使包装器变得懒惰也不起作用testProperty name lazy(testWithSetup)