34

I'm trying to do unit testing with xUnit.net. I want a 'Theory' test with '[InlineData]' which includes 'decimals':

[Theory]
[InlineData(37.60M)]
public void MyDecimalTest(decimal number)
{
    Assert.Equal(number, 37.60M);
}

This is not possible because you cannot create a decimal as a constant.

Question:
Is there a workaround for this?

Tim Pohlmann
  • 4,140
  • 3
  • 32
  • 61

4 Answers4

40

You should be able use the String value in the Attribute and set the Parameter type to Decimal, it get's converted automatically by the Test Framework as far as I can tell.

[Theory]
[InlineData("37.60")]
public void MyDecimalTest(Decimal number)
{
    Assert.Equal(number, 37.60M);
}

If this doesn't work then you can manually convert it by passing in a String parameter.

[Theory]
[InlineData("37.60")]
public void MyDecimalTest(String number)
{
    var d = Convert.ToDecimal(number);
    Assert.Equal(d, 37.60M);
}
DaveShaw
  • 52,123
  • 16
  • 112
  • 141
  • 1
    Nice idea. A little cleaner than casting the other value to double as well. Still hacky though. – Tim Pohlmann Jun 16 '16 at 09:06
  • @TimPohlmann I've updated my answer based on further experiments, where the tests pass on my machine – DaveShaw Jun 16 '16 at 09:14
  • 1
    Yeah this works. I tried it before but had a different issue failing and I just assumed it had converted it to a double. My bad. Thanks! – Tim Pohlmann Jun 16 '16 at 09:17
  • 3
    Consider `Convert.ToDecimal(number, NumberFormatInfo.InvariantInfo)` or equivalently `Convert.ToDecimal(number, CultureInfo.InvariantCulture)` if there is a possibility the current culture uses a different number format. Otherwise this may come out as 3760 (three thousand seven hundred and sixty). – Jeppe Stig Nielsen Jun 16 '16 at 09:36
  • 4
    In order to first code snippet, for me it doesn't compile. `The value is not convertible to the method parameter 'number' of type 'decimal'.` – Piotr Kwiatek Jan 03 '18 at 11:09
  • @PiotrKwiatek - It should compile, but could fail to run. See Jeppe's comment. As I cannot see how xunit does the conversion I'm guessing it must be a culture related thing. You may need to use your culture's decimal point character instead of `.`. – DaveShaw Jan 03 '18 at 22:43
22

Instead of InlineData, use MemberData as shown here. This gives you much greater flexibility in setting up multiple tests and allows the use of decimals or any other non-constant type.

public class CalculatorTests  
{

    public static TheoryData<decimal, decimal, decimal> Data =>
        new()
        {
            { 1.2M, 2.1M, 3.3M },
            { -4.000M, -6.123M, -10.123M }
        };

    [Theory]
    [MemberData(nameof(Data))]
    public void CanAddTheoryMemberDataProperty(decimal value1, decimal value2, decimal expected)
    {
        var calculator = new Calculator();

        var result = calculator.Add(value1, value2);

        Assert.Equal(expected, result);
    }
}
Ben
  • 123
  • 6
StillLearnin
  • 1,391
  • 15
  • 41
3

The NUnit solution (Google landed me here) The accepted answers gave me some ideas so after some research came up with with help from NUnit Sequential Attribute with arrays in Values. The nameof expression is a c# 7 expression

[TestFixture]
public class CalculatorTests
{

    public static IEnumerable<object[]> Data =>
        new List<object[]>
        {
            new object[] { 1.2M, 2.1M, 3.3M },
            new object[] { -4.000M, -6.123M, -10.123M }
        };

    [Test]
    [TestCaseSource(nameof(Data))]
    public void CanAddTheoryMemberDataProperty(decimal value1, decimal value2, decimal expected)
    {
        var calculator = new Calculator();

        var result = calculator.Add(value1, value2);

        Assert.AreEqual(expected, result);
    }
}
PBo
  • 399
  • 3
  • 6
2

As @StillLearning already suggested you can use the MemberData attribute. Nowadays there is the TheoryData<> type to make your input typesafe.

I (currently) cannot edit that answer so I'm posting it as another answer.

public class CalculatorTests  
{

    public static TheoryData<decimal, decimal, decimal> Data =>
        new()
        {
            { 1.2M, 2.1M, 3.3M },
            { -4.000M, -6.123M, -10.123M }
        };

    [Theory]
    [MemberData(nameof(Data))]
    public void CanAddTheoryMemberDataProperty(decimal value1, decimal value2, decimal expected)
    {
        var calculator = new Calculator();

        var result = calculator.Add(value1, value2);

        Assert.Equal(expected, result);
    }
}
Ben
  • 123
  • 6