Как проверить с decimal.MaxValue?

Рассмотрим следующий тест:

public void FooTest(decimal? val)
{
    Check.That(true).IsTrue();
}

Я хочу запустить этот тест с экстремальными значениями (т.е. MaxValue и MinValue).

[TestCase(decimal.MaxValue)]

Это приводит к следующей ошибке: Аргумент атрибута должен быть константным выражением, выражением типаof или выражением создания массива типа параметра атрибута

[TestCase(79228162514264337593543935)]

Теперь я получаю это: интегральная константа слишком велика

Последняя отчаянная попытка:

[TestCase(79228162514264337593543935M)]

Очевидно, я получаю это из-за приведения: Аргумент атрибута должен быть константным выражением, выражением типаof или выражением создания массива типа параметра атрибута

Как написать unit test с decimal.MaxValue в качестве параметра? Я мог написать конкретный тест для этого проблемного случая, но я хотел бы знать, есть ли способ написать TestCase, как это.

Ответы

Ответ 1

Decimal.MaxValue не является константой, это поле static readonly. Это означает, что вы не можете использовать его в атрибутах, поскольку атрибуты требуют констант. Вам придется жестко закодировать его.

Visual studio сделает вид const, но на самом деле не.

bool isConstant = typeof (decimal)
    .GetField("MaxValue", BindingFlags.Static | BindingFlags.Public)
    .IsLiteral;
//isConstant will be false :(

Ответ 2

Теперь, когда все остальные сказали, почему эта проблема возникает, ваш код должен использовать атрибут TestCaseSource для записи теста:

private static object[] TestValues = 
{
    new object[]{ Decimal.MaxValue },
    new object[]{ Decimal.MinValue }
};

[TestCaseSource("TestValues")]
public void FooTest(decimal value)
{
    Assert.That(value, Is.EqualTo(Decimal.MaxValue));
}

Ответ 3

Не имеет значения, пытаетесь ли вы использовать [TestCase(Decimal.MaxValue)] или используйте литерал как [TestCase(1m)]. Ни один из них не будет работать.

В соответствии со спецификацией С# (17.1.3, Типы параметров атрибутов):

Типы позиционных и именованных параметров для класса атрибута ограничены типами параметров атрибутов, которые:
• Один из следующих типов: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
• Тип объекта.
• Тип System.Type.
• Тип перечисления, если он имеет общедоступную доступность, и типы, в которых он вложен (если есть), также имеют общедоступную доступность (§17.2).
• Одномерные массивы вышеуказанных типов.

Обратите внимание на отсутствие десятичного числа в элементе первого списка.

Сообщение об ошибке немного вводит в заблуждение, поскольку в той же спецификации также указывается, что decimal может быть константным выражением (7.19).

Но если вы посмотрите код IL при создании decimal, вы увидите, что он вызывает вызов конструктора: newobj System.Decimal..ctor. И это в отличие от других литералов, например. ldc.r8 33 33 33 33 33 33 F3 3F для var a = 1.2;.