You may have a bunch of tests that are very similar, and you don’t want to repeat yourself so many times. In FsCheck you can “and” properties with the
.&. operator and label failures with either of the
|@ operators. The only problem is the first failing property will trigger all the subsequent labels to write as well. Here’s a little work-around to that situation:
1: 2: 3: 4: 5: 6: 7:
[<Test>] let ``returns expected length``() = Check.VerboseThrowOnFailure ( (1 = 1) |@ sprintf "1 != 2" .&. (2 = 3) |@ sprintf (if false then "" else "2 != 3") .&. (3 = 3) |@ sprintf (if (3 = 3) then "" else "3 != 4") .&. (4 = 5) |@ sprintf (if false then "" else "4 != 5") )
Remember the code to the left of
|@ is an FsCheck
property, and the similar looking statement to the right is an F# expression returning a
bool, so you have to keep these two pieces of code in sync. Other than that hassle, this works and will only print labels from failing properties in your combined test.
Full name: Snippet.( returns expected length )
static member All : config:Config -> unit
static member All : config:Config * test:Type -> unit
static member Method : config:Config * methodInfo:MethodInfo * ?target:obj -> unit
static member One : config:Config * property:’Testable -> unit
static member One : name:string * config:Config * property:’Testable -> unit
static member Quick : property:’Testable -> unit
static member Quick : name:string * property:’Testable -> unit
static member QuickAll : unit -> unit
static member QuickAll : test:Type -> unit
static member QuickThrowOnFailure : property:’Testable -> unit
Full name: FsCheck.Check
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
Well, that sucks. Thanks for bringing it to attention.
It’s a consequence of the fixity of .&. and |@ being equal, which means that this get parsed somewhat counter-intuitively. If you put parenthesis around all the various parts of the .&. it no longer prints the other ones, only the first one that fails (it is a shortcutting and so in your example you’ll only see the 2 != 3).
I will have a look at the fixity definition of fsharp, sadly you can’t define those separately but they’re derived from the name somehow, so will need to deprecate or rename some operators to make it work.
I’ve committed the %> operator as a replacement labeling operator which will do what you want (I think) without workaround. Also, a simpler workaround is just to put parenthesis around each sub-property.
Pingback: F# Weekly #5, 2014 | Sergey Tihon's Blog