问题
For some reason when passing arguments to the test via TestCase
attrubute, I get the following error message about the first argument, which in this case is an array:
This is not a valid constant expression or custom attribute value
module GameLogicTest =
open FsUnit
open NUnit.Framework
open GameLogic.Examle
// This is not a valid constant expression or custom attribute value
[<TestCase( [| 1; 2; 3 |], 3, 1,1)>]
let ``let example.`` (a, m, h, c) =
a
|> proof1 m
|> should equal (h,c)
But when removing the last argument, from both the attribute and the method itself, it all works just fine.
[<TestCase( [| 1; 2; 3 |], 3, 1)>]
let ``let example.`` (a, m, h) =
a
|> proof1 m
|> should equal (h,1)
What am I doing wrong? Preferably I would also define a tuple of int * int
but it doesn't seem to work either.
回答1:
CLI has a restriction regarding kinds of attribute parameters:
- primitive: bool, int, float, etc
- enums
- strings
- type references: System.Type
- 'kinda objects': boxed (if needed) representation of types from above
- one dimensional array of one of types from above (ie. no nested arrays allowed)
So we can conclude at this point that you can not use tuple as an attribute parameter's type.
From here starts my speculations, so none of below can be true.
I played a bit with different attributes and found that F# compiler starts complain about an every array parameter, when attribute has variable number of arguments (params). For example, if I define the following attribute
public class ParamsAttribute : Attribute
{
public ParamsAttribute(params object[] parameters)
{}
}
and try to use it from F# code, I'll get an error:
[<Params(1, 2, 3)>] // here everything is OK
let x () = ()
[<Params([|1; 2; 3|])>] // the same error as you have
let y () = ()
I guess the compiler can consider params arguments as an array and therefore does not allow to define 'nested' array in it. But as I said, it is a pure speculation.
回答2:
Instead of an array parameter use a string parameter. Concatenate all the terms into the string and pass it in.
Use String.Split to convert the string parameter into a string array
then use Array.map
to convert to the array of choice.
[<TestCase([|1, 2, 3|], 4, 5, 6)>]
let ``My Test``(param1: int[], param2: int, param3: int, param4: int) =
// My test code
Becomes
[<TestCase("1|2|3", 4, 5, 6)>]
let ``My Test``(param1: string, param2: int, param3: int, param4: int) =
let stringArray = param1.Split('|', SplitStringOptions.None)
let intArray = Array.map int stringArray
// My test code
来源:https://stackoverflow.com/questions/28012156/parameterized-tests-in-f-this-is-not-a-valid-constant-expression