Why am I receiving a "No arguments provided" error on a property-based test?

1.6k views Asked by At

The following test fails:

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``

Error:

Message: No arguments were provided

I thought FsCheck would provide the argument for me on each test iteration.

I am referencing the following documentation.

2

There are 2 answers

3
Mark Seemann On BEST ANSWER

Here's a version for xUnit.net that sort of works:

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``

When you use it that way, the first function is the property, and it can take arguments.

The [<Fact>]-annotated function takes no argument.

The problem with that approach is that Check.Quick doesn't cause the test to fail if the property doesn't hold. It only outputs that the property was falsified. If you want the test to fail if the property is falsified, you should use 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``

Another issue is that there's no reason to write this in such a verbose fashion. Here's a more compact way to write the same property:

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)
0
Kurt Schelfthout On

Mark's answer is great, but just to clarify the NUnit situation.

FsCheck.NUnit provides the PropertyAttribute to adorn test methods that take an argument. It does not hook into the normal NUnit TestAttribute. So in other words your example has a normal NUnit test that takes an argument - NUnit cannot cope with this. Tests that take an argument that you want FsCheck to generate values for look like this:

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

The other option - if you don't want to wrestle with NUnit and FsCheck.NUnit, as Mark says it can be quite brittle mostly due to NUnit 2's quite annoying plugin model - is to not use FsCheck.NUnit at all, and instead use normal NUnit tests. Use QuickCheckThrowOnFailure to signal test failures from FsCheck to NUnit via an exception:

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

Your example somehow mixed these two options.

Related Questions in F#