In F# how do you pass a collection to xUnit's InlineData attribute

前端 未结 6 785
故里飘歌
故里飘歌 2021-01-02 00:28

I would like to be about to use a list, array, and/or seq as a parameter to xUnit\'s InlineData.

In C# I can do this:

using Xunit; //2.1.0

namespace C         


        
6条回答
  •  醉话见心
    2021-01-02 01:14

    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: [], so the direct answer to your question is:

    module UsingInlineData =
        []
        []  
        []  
        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 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 |] ])
    
    []
    [)>]
    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)
    
    [)>]
    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) :-

    []
    let v3 (a : int, b : int) : unit = Assert.NotEqual(a, b)
    

    The key thing to get right is to put the : seq (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()
        do  this.Add(3, 4)
            this.Add(32, 42)
    
    [)>]
    let v2 (a : int, b : int) : unit = Assert.NotEqual(a, b)
    

    That also type-checks each argument.

提交回复
热议问题