我想使用列表、数组和/或序列作为 xUnit 的 InlineData 的参数.
I would like to be about to use a list, array, and/or seq as a parameter to xUnit's InlineData.
在 C# 中,我可以这样做:
In C# I can do this:
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# 中,我有这个:
In F# I have this:
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# 代码给出以下构建错误:
The F# code give the following build errors:
Library1.fs (13, 16):这不是有效的常量表达式或自定义属性值
Library1.fs (13, 16): This is not a valid constant expression or custom attribute value
Library1.fs (18, 16):这不是有效的常量表达式或自定义属性值
Library1.fs (18, 16): This is not a valid constant expression or custom attribute value
参考第二和第三测试理论.
Referring to the 2nd and 3rd test theories.
是否可以使用 xUnit 将集合传递给 InlineData 属性?
Is it possible to use xUnit to pass in collections to the InlineData attribute?
推荐答案InlineDataAttribute 依赖于 C# params 机制.这就是在 C# 中启用 InlineData 的默认语法的原因:-
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})]只是编译器将上述内容翻译成的内容.如果您走得更远,您将遇到与 CLI 实际启用的内容相同的限制 - 最重要的是,在 IL 级别,使用属性构造函数意味着所有内容都需要在编译时归结为常量.与上述语法等效的 F# 很简单:[<InlineData(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)虽然我无法避免对@bytebuster 的例子进行重复:) 如果我们定义一个助手:-
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那么(如果我们愿意放弃懒惰),我们可以滥用list来避免必须使用seq/yield来赢得代码高尔夫:-
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)但是seq的原始语法可以做得足够干净,所以没有必要像上面那样使用它,而是我们这样做:
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)然而,对我来说,xUnit v2 最惯用的方式是直接使用 MemberData(类似于 xUnit v1 的 PropertyData,但一般也适用于字段):-
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)正确的关键是将 : seq(或 : obj[] seq)放在序列的声明上,否则 xUnit 将抛出在你身边.
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.
xUnit 2 的更高版本包括一个类型化的 TheoryData,它允许您编写:
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.
更多推荐
在 F# 中,如何将集合传递给 xUnit 的 InlineData 属性
发布评论