gpt4 book ai didi

.net - 在 F# 中,如何将集合传递给 xUnit 的 InlineData 属性

转载 作者:行者123 更新时间:2023-12-04 05:02:32 25 4
gpt4 key购买 nike

我想使用列表、数组和/或 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);
}
}
}
在 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): This is not a valid constant expression or custom attribute value

Library1.fs (18, 16): This is not a valid constant expression or custom attribute value


引用第二和第三测试理论。
是否可以使用 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赢得代码高尔夫:-
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 v1 的 PropertyData 但概括为也适用于领域):-
[<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)

这也会对每个参数进行类型检查。

关于.net - 在 F# 中,如何将集合传递给 xUnit 的 InlineData 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35026735/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com