Dot-Net
在 F# 中,如何將集合傳遞給 xUnit 的 InlineData 屬性
我想使用列表、數組和/或序列作為 xUnit 的 InlineData 的參數。
在 C# 中,我可以這樣做:
using Xunit; //2.1.0 namespace CsTests { public class Tests { [Theory] [InlineData(new[] {1, 2})] public void GivenCollectionItMustPassItToTest(int[] coll) { Assert.Equal(coll, coll); } } }在 F# 中,我有這個:
namespace XunitTests module Tests = open Xunit //2.1.0 [<Theory>] [<InlineData(8)>] [<InlineData(42)>] let ``given a value it must give it to the test`` (value : int) = Assert.Equal(value, value) [<Theory>] [<InlineData([1; 2])>] let ``given a list it should be able to pass it to the test`` (coll : int list) = Assert.Equal<int list>(coll, coll) [<Theory>] [<InlineData([|3; 4|])>] let ``given an array it should be able to pass it to the test`` (coll : int array) = Assert.Equal<int array>(coll, coll)F# 程式碼給出以下建構錯誤:
Library1.fs (13, 16):這不是有效的常量表達式或自定義屬性值
Library1.fs (18, 16):這不是有效的常量表達式或自定義屬性值
參考第 2 和第 3 測試理論。
是否可以使用 xUnit 將集合傳遞給 InlineData 屬性?
InlineDataAttribute依靠 C#params機制。這就是在 C# 中啟用 InlineData 的預設語法的原因:-[InlineData(1,2)]您的數組構造版本:-
[InlineData( new object[] {1,2})]就是編譯器將上述內容翻譯成的內容。再進一步,您將遇到 CLI 實際啟用的相同限制 - 底線是在 IL 級別,使用屬性建構子意味著所有內容都需要在編譯時歸結為常量。上述語法的 F# 等價物很簡單:
[<InlineData(1,2)>],因此您的問題的直接答案是:module UsingInlineData = [<Theory>] [<InlineData(1, 2)>] [<InlineData(1, 1)>] let v4 (a : int, b : int) : unit = Assert.NotEqual(a, b)不過,我無法避免重複@bytebuster 的範例:) 如果我們定義一個助手:-
type ClassDataBase(generator : obj [] seq) = interface seq<obj []> with member this.GetEnumerator() = generator.GetEnumerator() member this.GetEnumerator() = generator.GetEnumerator() :> System.Collections.IEnumerator然後(如果我們願意放棄懶惰),我們可以濫用
list以避免使用seq/yield來贏得程式碼 golf:-type MyArrays1() = inherit ClassDataBase([ [| 3; 4 |]; [| 32; 42 |] ]) [<Theory>] [<ClassData(typeof<MyArrays1>)>] let v1 (a : int, b : int) : unit = Assert.NotEqual(a, b)但是可以使原始語法
seq足夠乾淨,因此不需要像上面那樣使用它,而是我們這樣做: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)但是,對我來說,xUnit v2 最慣用的方法是直接使用
MemberData(類似於 xUnit v1PropertyData,但也適用於欄位):-[<Theory; MemberData("values")>] let v3 (a : int, b : int) : unit = Assert.NotEqual(a, b)正確的關鍵是將
: seq<obj>(或: obj[] seq)放在序列的聲明中,否則 xUnit 會扔給您。xUnit 2 的更高版本包括一個類型化的 TheoryData,它允許您編寫:
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)這也會對每個參數進行類型檢查。