InlineDataAttribute
leans on the C# params
mechanism. This is what enables the default syntax of InlineData in C# :-
[InlineData(1,2)]
Your version with array construction:-
[InlineData( new object[] {1,2})]
is simply what the compiler translates the above into. The minute you go further, you'll run into the same restrictions on what the CLI will actually enable - the bottom line is that at the IL level, using attribute constructors implies that everything needs to be boiled down to constants at compile time. The F# equivalent of the above syntax is simply: [<InlineData(1,2)>]
, so the direct answer to your question is:
module UsingInlineData =
[<Theory>]
[<InlineData(1, 2)>]
[<InlineData(1, 1)>]
let v4 (a : int, b : int) : unit = Assert.NotEqual(a, b)
I was unable to avoid riffing on @bytebuster's example though :) If we define a helper:-
type ClassDataBase(generator : obj [] seq) =
interface seq<obj []> with
member this.GetEnumerator() = generator.GetEnumerator()
member this.GetEnumerator() =
generator.GetEnumerator() :> System.Collections.IEnumerator
Then (if we are willing to forgo laziness), we can abuse list
to avoid having to use seq
/ yield
to win the code golf:-
type MyArrays1() =
inherit ClassDataBase([ [| 3; 4 |]; [| 32; 42 |] ])
[<Theory>]
[<ClassData(typeof<MyArrays1>)>]
let v1 (a : int, b : int) : unit = Assert.NotEqual(a, b)
But the raw syntax of seq
can be made sufficiently clean, so no real need to use it as above, instead we do:
let values : obj[] seq =
seq {
yield [| 3; 4 |]
yield [| 32; 42 |] // in recent versions of F#, `yield` is optional in seq too
}
type ValuesAsClassData() =
inherit ClassDataBase(values)
[<Theory; ClassData(typeof<ValuesAsClassData>)>]
let v2 (a : int, b : int) : unit = Assert.NotEqual(a, b)
However, most idiomatic with xUnit v2 for me is to use straight MemberData
(which is like xUnit v1's PropertyData
but generalized to also work on fields) :-
[<Theory; MemberData("values")>]
let v3 (a : int, b : int) : unit = Assert.NotEqual(a, b)
The key thing to get right is to put the : seq<obj>
(or : obj[] seq
) on the declaration of the sequence or xUnit will throw at you.
Later versions of xUnit 2 include a typed TheoryData, which lets you write:
type Values() as this =
inherit TheoryData<int,int>()
do this.Add(3, 4)
this.Add(32, 42)
[<Theory; ClassData(typeof<Values>)>]
let v2 (a : int, b : int) : unit = Assert.NotEqual(a, b)
That also type-checks each argument.
Current xUnit v2 releases let you replace the Add
with constructor calls, e.g.:
type Values() =
inherit TheoryData<_, _>([
3, 4
32, 42 ])
[<Theory; ClassData(typeof<Values>)>]
let v2 (a : int, b : int) : unit = Assert.NotEqual(a, b)