我想要将列表,数组和/或seq用作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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在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)
Run Code Online (Sandbox Code Playgroud)
F#代码提供以下构建错误:
Library1.fs(13,16):这不是有效的常量表达式或自定义属性值
Library1.fs(18,16):这不是有效的常量表达式或自定义属性值
参考第二和第三测试理论.
是否可以使用xUnit将集合传递给InlineData属性?
如本问题所述,您只能使用文字InlineData.列表不是文字.
但是,xUnit提供了ClassData哪些似乎可以满足您的需求.
这个问题讨论了C#的同样问题.
为了ClassData与测试一起使用,只需要创建一个数据类seq<obj[]>:
type MyArrays () =
let values : seq<obj[]> =
seq {
yield [|3; 4|] // 1st test case
yield [|32; 42|] // 2nd test case, etc.
}
interface seq<obj[]> with
member this.GetEnumerator () = values.GetEnumerator()
member this.GetEnumerator () =
values.GetEnumerator() :> System.Collections.IEnumerator
module Theories =
[<Theory>]
[<ClassData(typeof<MyArrays1>)>]
let ``given an array it should be able to pass it to the test`` (a : int, b : int) : unit =
Assert.NotEqual(a, b)
Run Code Online (Sandbox Code Playgroud)
虽然这需要一些手动编码,但您可以重复使用数据类,这似乎在实际项目中很有用,我们经常针对相同的数据运行不同的测试.
InlineDataAttribute倾向于C#params机制.这是在C#中启用InlineData的默认语法的原因: -
[InlineData(1,2)]
Run Code Online (Sandbox Code Playgroud)
您的版本与数组结构: -
[InlineData( new object[] {1,2})]
Run Code Online (Sandbox Code Playgroud)
简单来说就是编译器将上述内容翻译成的内容.一旦你走得更远,你将对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)
Run Code Online (Sandbox Code Playgroud)
我无法避免在@ bytebuster的例子上匆匆而过:)如果我们定义一个帮助器: -
type ClassDataBase(generator : obj [] seq) =
interface seq<obj []> with
member this.GetEnumerator() = generator.GetEnumerator()
member this.GetEnumerator() =
generator.GetEnumerator() :> System.Collections.IEnumerator
Run Code Online (Sandbox Code Playgroud)
然后(如果我们愿意放弃懒惰),我们可以滥用list以避免使用seq/ yield赢得代码高尔夫: -
type MyArrays1() =
inherit ClassDataBase([ [| 3; 4 |]; [| 32; 42 |] ])
[<Theory>]
[<ClassData(typeof<MyArrays1>)>]
let v1 (a : int, b : int) : unit = Assert.NotEqual(a, b)
Run Code Online (Sandbox Code Playgroud)
但原始语法seq可以做得足够干净,所以不需要像上面那样使用它,而是我们这样做:
let values : obj array seq =
seq {
yield [| 3; 4 |]
yield [| 32; 42 |]
}
type ValuesAsClassData() =
inherit ClassDataBase(values)
[<Theory; ClassData(typeof<ValuesAsClassData>)>]
let v2 (a : int, b : int) : unit = Assert.NotEqual(a, b)
Run Code Online (Sandbox Code Playgroud)
但是,xUnit v2对我来说最常用的是直接使用MemberData (就像xUnit v1一样,PropertyData但是也可以在字段上使用): -
[<Theory; MemberData("values")>]
let v3 (a : int, b : int) : unit = Assert.NotEqual(a, b)
Run Code Online (Sandbox Code Playgroud)
正确的关键是将: seq<obj>(或: obj array seq)放在序列的声明上,否则xUnit将向你抛出.
您还可以使用没有类的成员数据:
let memberDataProperty = seq {
yield [|"param1":> Object; param2 :> Object; expectedResult :> Object |]
}
[<Theory; MemberData("memberDataProperty")>]
let ``Can use MemberData`` param1 param2 expectedResult = ...
Run Code Online (Sandbox Code Playgroud)
您可以在FSharp.Reflection此处使用命名空间以获得良好的效果。考虑一些isAnswer : (string -> int -> bool)您想用几个例子测试的假设函数。
这是一种方法:
open FSharp.Reflection
open Xunit
type TestData() =
static member MyTestData =
[ ("smallest prime?", 2, true)
("how many roads must a man walk down?", 41, false)
] |> Seq.map FSharpValue.GetTupleFields
[<Theory; MemberData("MyTestData", MemberType=typeof<TestData>)>]
let myTest (q, a, expected) =
Assert.Equals(isAnswer q a, expected)
Run Code Online (Sandbox Code Playgroud)
关键是|> Seq.map FSharpValue.GetTupleFields线。它接受元组列表(您必须使用元组来允许不同的参数类型)并将其转换为IEnumerable<obj[]>XUnit 期望的类型。
| 归档时间: |
|
| 查看次数: |
1849 次 |
| 最近记录: |