Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test with decimal.MaxValue?

Consider the following test:

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

I want to run this test with extreme values (i.e. MaxValue and MinValue).

[TestCase(decimal.MaxValue)]

This outputs the following error : An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

[TestCase(79228162514264337593543935)]

I get this one now : Integral constant is too large

One last desperate try:

[TestCase(79228162514264337593543935M)]

Obviously I get this one because of the cast : An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

How does one write a unit test with decimal.MaxValue as a parameter? I could write a specific test for this problematic case but I would like to know if there's a way to write a TestCase like this.

like image 285
Max Avatar asked Aug 04 '14 09:08

Max


3 Answers

Now that all others have said, why this problem occurs, your code should use the TestCaseSource attribute to write your test:

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));
}
like image 185
Oliver Avatar answered Oct 23 '22 20:10

Oliver


Decimal.MaxValue is not a constant, it is a static readonly field. Which means you can't use it in attributes as attributes require constants. You'll have to hard code it.

Visual studio will pretend it as a const but it is actually not.

bool isConstant = typeof (decimal)
    .GetField("MaxValue", BindingFlags.Static | BindingFlags.Public)
    .IsLiteral;
//isConstant will be false :(
like image 31
Sriram Sakthivel Avatar answered Oct 23 '22 19:10

Sriram Sakthivel


It doesn't matter whether you try to use [TestCase(Decimal.MaxValue)] or use a literal like [TestCase(1m)]. Neither will work.

According to the C# specification (17.1.3, Attribute parameter types):

The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:
• One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
• The type object.
• The type System.Type.
• An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility (§17.2).
• Single-dimensional arrays of the above types.

Notice the absence of decimal in the first list item.

The error message is a bit misleading because same specification also says that a decimal can be a constant expression (7.19).

But if you look at the IL code when creating a decimal you'll see that it actually invokes a constructor call: newobj System.Decimal..ctor. And that's unlike other literals, e.g. ldc.r8 33 33 33 33 33 33 F3 3F for var a = 1.2;.

like image 7
Dirk Avatar answered Oct 23 '22 18:10

Dirk