如果随机生成的输入没有用,我如何重新尝试基于 属性 的测试?

How can I re-try a property-based-test if the randomly-generated inputs are not useful?

我对单元测试一窍不通。我已经从 Nuget 安装了 FsCheck.NunitNUnitTestAdapter,并且我正在尝试进行基于 属性 的测试,主要受到 the inestimable Scott Wlaschin.

的启发

我正在使用 [<Property>] 属性,我希望能够 "skip" 不符合测试要求的输入:

[<Property(MaxTest=10)>]
let ``Calling unzipTo with an invalid destination will yield a failure.`` badDest =
    if Directory.Exists(badDest)
    then // somehow skip to the next randomized input
    else // do the actual test

最简单的方法是什么?

我更喜欢 FsCheck/NUnit 的答案(如果存在的话),但我也会考虑任何其他框架,其测试可以是 运行 in Visual Studio。 (我以为我看到了一些框架,其中有一个简单的函数可以做到这一点,但我不知道它是什么。)

到目前为止,我更喜欢 FsCheck.NUnit,因为它可以为 F# 类型(区分联合等)生成随机输入,而无需额外的工作。

我不是很熟悉 F# 或 fscheck,但如果您觉得这些状态更合适,NUnit 会提供 Assert.Ignore() function, which will immediately stop the test and marked it as "ignored." You could also use Assert.Inconclusive() or Assert.Pass()

你应该可以这样做:

open FsCheck
open FsCheck.Xunit

[<Property(MaxTest=10)>]
let ``Calling unzipTo with an invalid destination will yield a failure.`` badDest =
    (not Directory.Exists(badDest)) ==> lazy
    // do the actual test

第一行是布尔条件,==>FsCheck模块定义的自定义运算符。如果 right-hand 端的条件计算为 true.

,它只会强制计算惰性表达式

但是,请考虑重构此测试,使其不依赖于文件系统。文件系统是持久化的,所以会自动创建一个Persistent Fixture,也就是a lot of trouble to manage;并非无法应对,但最好避免。

此示例使用 FsCheck.Xunit,但 IIRC FsCheck.Nunit 的工作方式相同。不过,您应该认真考虑使用 FsCheck.Xunit 而不是 FsCheck.Nunit。 NUnit 2 的可扩展性模型非常差,这意味着大多数尝试扩展 NUnit 的 Glue 库都存在很多问题。这不是 FsCheck.Nunit 的问题,而是 NUnit 本身的问题,但它会给您带来很多麻烦。

FsCheck.Prop.discard() 似乎在做我想做的事情——当我 运行 进行日志记录测试时,我可以看到一些尝试被丢弃了,但是 10 运行 没有完成被丢弃。

==> 运算符用于 运行 与 FsCheck.Quick 或类似的测试。但是,这需要惰性部分采用“可测试”的格式,我目前正在编写的测试只是 <inputs>->unit.