【问题标题】:Why am I receiving a "No arguments provided" error on a property-based test?为什么我在基于属性的测试中收到“未提供参数”错误?
【发布时间】:2025-11-24 12:05:02
【问题描述】:

以下测试失败:

open FsCheck
open FsCheck.NUnit
open NUnit.Framework

let ``Property: double negation equals no negation`` list =
    list = List.rev (List.rev list)

[<Test>]
let ``reversing list two times is equal to not reversing list at all`` list = 
    Check.Quick ``Property: double negation equals no negation``

错误:

消息:未提供任何参数

我认为 FsCheck 会在每次测试迭代中为我提供参数。

我引用了以下documentation

【问题讨论】:

  • 与此问题无关。麦吉尔的同学们在这里倾倒assignment 4问题,但他们学会了在得到答案后删除问题。请注意这一点。
  • 您使用的是哪个版本的 NUnit? Nunit 3.x 是 2.x 的重大变化,有重大变化;以至于我不得不花一天时间学习如何使用它。
  • 我的单元测试仍然通过。这只是我尝试基于属性的测试失败。我想我可以弄乱 FsCheck.NUnit 版本。目前设置为最新的 v2.24
  • 我尝试了不同版本的 FsCheck.NUnit 都没有成功。
  • 你愿意迁移到 NUnit 3.x 吗?如果是这样,我会花一些时间来回答您的问题。

标签: f# nunit-2.5 fscheck


【解决方案1】:

这是一个适用于 xUnit.net 的版本:

open FsCheck
open Xunit

let ``Property: double negation equals no negation`` list =
    list = List.rev (List.rev list)

[<Fact>]
let ``reversing list two times is equal to not reversing list at all`` () = 
    Check.Quick ``Property: double negation equals no negation``

当你这样使用它时,第一个函数是属性,它可以接受参数。

[&lt;Fact&gt;]-annotated 函数不接受任何参数。

这种方法的问题在于,如果属性不成立,Check.Quick 不会导致测试失败。它仅输出该属性被伪造。如果您希望在属性被伪造的情况下测试失败,您应该使用Check.QuickThrowOnFailure

open FsCheck
open Xunit

let ``Property: double negation equals no negation`` list =
    list = List.rev (List.rev list)

[<Fact>]
let ``reversing list two times is equal to not reversing list at all`` () = 
    Check.QuickThrowOnFailure ``Property: double negation equals no negation``

另一个问题是没有理由以如此冗长的方式编写此代码。这是编写相同属性的更紧凑的方法:

open FsCheck
open Xunit

[<Fact>]
let ``reversing list two times is equal to not reversing list at all`` () = 
    Check.QuickThrowOnFailure <| fun (l : int list) ->
        l = List.rev (List.rev l)

【讨论】:

  • 嗯...我刚刚意识到甚至没有发现这种特定的测试类型。我认为它已解决,因为我的其他单元测试运行并且我看到了一个绿色条。
  • 我想我需要一个 XUnit 测试适配器?
  • 在写我的答案时,我故意避开了 NUnit 2.x,因为它有很多问题。也就是说,上面的测试只是一个正常的测试;你会注意到我没有导入FsCheck.Xunit。不过,我见过的所有 NUnit 2.x 测试示例在类中都有测试方法,并且该类使用 [TestFixture] 属性进行注释。 NUnit 2.x 甚至可以在 F# 模块中工作吗?所有这些在 NUnit 3 中可能会更好,但我对那个版本不太熟悉。
【解决方案2】:

马克的回答很好,但只是为了澄清 NUnit 的情况。

FsCheck.NUnit 提供了PropertyAttribute 来修饰带有参数的测试方法。它不会挂接到普通的 NUnit TestAttribute。所以换句话说,你的例子有一个正常的 NUnit 测试,它需要一个参数 - NUnit 无法处理这个问题。采用您希望 FsCheck 为其生成值的参数的测试如下所示:

[<Property>]
let ``Property: double negation equals no negation`` list =
    list = List.rev (List.rev list)

另一个选择 - 如果你不想与 NUnit 和 FsCheck.NUnit 搏斗,正如 Mark 所说,它可能很脆弱,主要是由于 NUnit 2 的插件模型非常烦人 - 是根本不使用 FsCheck.NUnit,而是使用普通的 NUnit 测试。使用QuickCheckThrowOnFailure 通过异常将测试失败从 F​​sCheck 发送到 NUnit:

[<Test>]
let ``reversing list two times is equal to not reversing list at all`` () = 
    Check.QuickThrowOnFailure ``Property: double negation equals no negation``

您的示例以某种方式混合了这两个选项。

【讨论】:

    最近更新 更多