Parameterized tests in f# - This is not a valid constant expression
Asked Answered
B

2

8

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.

Blunderbuss answered 18/1, 2015 at 16:38 Comment(1)
I was just looking into the same error message in a different context (using the FSharp.Data JsonProvider). I had to add a special indicator above the binding I created (which was [<Literal>]). I'm not quite sure what this does to be honest, but perhaps this could be applied here as well?Cartwell
I
7

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.

Inconsequential answered 18/1, 2015 at 22:32 Comment(0)
C
1

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
Collaborate answered 11/11, 2015 at 8:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.