如何将值传递给接受可为空的十进制的xUnit测试?

时间:2018-07-26 17:54:23

标签: c# xunit

我的一个单元测试具有以下签名:

public void FooWithFilter(string fooId, decimal? amount)

当我使用null测试它时,它会起作用:

[InlineData("123", null)]

但是如果我使用实际值,例如:

[InlineData("123", 610)]

我得到一个错误:

System.ArgumentException Object of type 'System.Int32' cannot be 
converted to type 'System.Nullable`1[System.Decimal]'.

我尝试使用610M作为属性值,但是不允许将其用作属性值:

An attribute argument must be a constant expression, type of expression
or array creation expression of an attribute parameter type.

这里是否可以使用可为空的小数?

3 个答案:

答案 0 :(得分:2)

如注释中所述,您不能在此处使用decimal,因为decimal不是属性参数值允许的类型之一。

但是,xUnit提供了一种更灵活的方法,可以使用ClassData将参数值传递给测试方法:

[Theory]
[ClassData(FooDataGenerator)]
public void FooWithFilter(string fooId, decimal? amount)

要使用此功能,您只需要定义一个扩展IEnumerable<object[]>并产生所需输入值的类:

public class FooDataGenerator : IEnumerable<object[]>
{
    private readonly List<object[]> _data = new List<object[]>
    {
        new object[] {"123", null},
        new object[] {"123", 610M}
    };

    public IEnumerator<object[]> GetEnumerator() => _data.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

关于将值传递给xUnit测试的各种方式的更多参考:
Creating Parameterised tests in xUnit
xUnit Theory: Working With InlineData, MemberData, ClassData

答案 1 :(得分:0)

除了JLRishe的答案,我建议从TheoryData或其通用交易对手TheoryData<>继承,这样我们可以获得强类型的测试数据和更简洁的代码。我发现文档在这方面有些薄。

[Theory]
[ClassData(typeof(FooDataGenerator))]
public void FooWithFilter(string fooId, decimal? expected)
{
    // Arrange // Act // Assert
}

public FooDataGenerator : TheoryData<string, decimal?>
{
    public FooDataGenerator()
    {
        this.Add("987", null);
        this.Add("123", 610m};
        // ...
    }
}

答案 2 :(得分:0)

一个简单的解决此问题的方法是将参数设置为double?并将其转换为小数?像这样

[Theory]
        [InlineData(1200, 1150, 50, 100)]
        [InlineData(1200.50, 1200.50, 0, 0)]
        [InlineData(1250.50, 1150, 0, 100.50)]
        [InlineData(1150, 1150, null, null)]
        [InlineData(0, null, null, null)]
        [InlineData(-50, null, 50, null)]
        [InlineData(50, null, null, 50)]

        public void SubTotal(double valorEsperado, double? valorTotal, double? valorFrete, double? valorDesconto) =>
            Assert.Equal((decimal)valorEsperado, PedidoBuilderTest.New
                                            .AtribuirValores((decimal?)valorTotal, (decimal?)valorFrete, (decimal?)valorDesconto)
                                            .Build().SubTotal);