Параметризованные тесты в F# - это недопустимое константное выражение

По какой-то причине при передаче аргументов в тест через TestCase attrubute, я получаю следующее сообщение об ошибке о первом аргументе, который в данном случае является массивом:

Это недопустимое константное выражение или значение пользовательского атрибута

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)

Но при удалении последнего аргумента как из атрибута, так и из самого метода все работает просто отлично.

[<TestCase( [| 1; 2; 3 |], 3, 1)>]
let ``let example.`` (a, m, h) = 
    a
    |> proof1 m
    |> should equal (h,1)

Что я делаю неправильно? Предпочтительно, я бы также определил кортеж int * int но, похоже, это тоже не работает.

2 ответа

CLI имеет ограничение относительно видов параметров атрибута:

  • примитив: bool, int, float и т. д.
  • перечислений
  • строки
  • Тип ссылки: System.Type
  • 'kinda objects': коробочное (при необходимости) представление типов сверху
  • одномерный массив одного из типов сверху (т.е. вложенные массивы не допускаются)

Таким образом, мы можем сделать вывод, что вы не можете использовать кортеж в качестве типа параметра атрибута.

Отсюда начинаются мои предположения, поэтому ни одно из нижеприведенного не может быть правдой.

Я немного поиграл с разными атрибутами и обнаружил, что компилятор F# начинает жаловаться на каждый параметр массива, когда атрибут имеет переменное количество аргументов (params). Например, если я определю следующий атрибут

public class ParamsAttribute : Attribute
{
    public ParamsAttribute(params object[] parameters)
    {}
}

и попробуйте использовать его из кода F#, я получу ошибку:

[<Params(1, 2, 3)>] // here everything is OK
let x () = ()

[<Params([|1; 2; 3|])>] // the same error as you have
let y () = ()

Я предполагаю, что компилятор может рассматривать аргументы params как массив и, следовательно, не позволяет определять в нем "вложенный" массив. Но, как я уже сказал, это чистое предположение.

Вместо параметра массива используйте строковый параметр. Объедините все члены в строку и передайте ее. Используйте String.Split, чтобы преобразовать строковый параметр в строковый массив, затем используйте Array.map преобразовать в массив выбора.

[<TestCase([|1, 2, 3|], 4, 5, 6)>]
let ``My Test``(param1: int[], param2: int, param3: int, param4: int) =
    // My test code

становится

[<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
Другие вопросы по тегам