C# xUnit测试引擎的InlineDataAttribute+可选方法参数

C# xUnit测试引擎的InlineDataAttribute+可选方法参数,c#,unit-testing,optional-parameters,xunit,optional-arguments,C#,Unit Testing,Optional Parameters,Xunit,Optional Arguments,当您没有在InlineDataAttribute中指定可选参数值时,是否可以使xUnit测试工作 例如: [Theory] [InlineData(1, true)] // works [InlineData(2)] // error void Test(int num, bool fast=true){} 是的。有很多方法可以通过重新定义一些原始的xunit属性来实现 下面的代码就是其中之一,这将给您一些想法 [AttributeUsage(AttributeTargets.Me

当您没有在InlineDataAttribute中指定可选参数值时,是否可以使xUnit测试工作

例如:

[Theory]
[InlineData(1, true)] // works
[InlineData(2)]       // error
void Test(int num, bool fast=true){}

是的。有很多方法可以通过重新定义一些原始的xunit属性来实现

下面的代码就是其中之一,这将给您一些想法

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class OptionalTheoryAttribute : TheoryAttribute
{
    protected override IEnumerable<ITestCommand> EnumerateTestCommands(IMethodInfo method)
    {
        var result = (List<ITestCommand>)base.EnumerateTestCommands(method);

        try
        {
            return TransferToSupportOptional(result, method);
        }
        catch (Exception ex)
        {
            result.Clear();
            result.Add(new LambdaTestCommand(method, () =>
                {
                    throw new InvalidOperationException(
                        String.Format("An exception was thrown while getting data for theory {0}.{1}:\r\n{2}",
                            method.TypeName, method.Name, ex)
                        );
                }));
        }
        return result;
    }

    private static IEnumerable<ITestCommand> TransferToSupportOptional(
        IEnumerable<ITestCommand> testCommands, IMethodInfo method)
    {
        var parameterInfos = method.MethodInfo.GetParameters();
        testCommands.OfType<TheoryCommand>().ToList().ForEach(
            testCommand => typeof(TheoryCommand)
                               .GetProperty("Parameters")
                               .SetValue(testCommand, GetParameterValues(testCommand, parameterInfos)));
        return testCommands;
    }

    private static object[] GetParameterValues(TheoryCommand testCommand, ParameterInfo[] parameterInfos)
    {
        var specifiedValues = testCommand.Parameters;
        var optionalValues = GetOptionalValues(testCommand, parameterInfos);

        return specifiedValues.Concat(optionalValues).ToArray();
    }

    private static IEnumerable<object> GetOptionalValues(TheoryCommand command, ParameterInfo[] parameterInfos)
    {
        return Enumerable.Range(command.Parameters.Length, parameterInfos.Length - command.Parameters.Length)
                         .ToList().Select(i =>
                             {
                                 EnsureIsOptional(parameterInfos[i]);
                                 return Type.Missing;
                             });
    }

    private static void EnsureIsOptional(ParameterInfo parameterInfo)
    {
        if (!parameterInfo.IsOptional)
        {
            throw new ArgumentException(string.Format(
                "The parameter '{0}' should be optional or specified from data attribute.",
                parameterInfo));
        }
    }
}

internal class LambdaTestCommand : TestCommand
{
    private readonly Assert.ThrowsDelegate lambda;

    public LambdaTestCommand(IMethodInfo method, Assert.ThrowsDelegate lambda)
        : base(method, null, 0)
    {
        this.lambda = lambda;
    }

    public override bool ShouldCreateInstance
    {
        get
        {
            return false;
        }
    }

    public override MethodResult Execute(object testClass)
    {
        try
        {
            lambda();
            return new PassedResult(testMethod, DisplayName);
        }
        catch (Exception ex)
        {
            return new FailedResult(testMethod, ex, DisplayName);
        }
    }
}

public class OptionalTheoryTest
{
    [OptionalTheory]
    [InlineData(1)]
    [InlineData(1, true)]
    public void TestMethod(int num, bool fast = true)
    {
        // Arrange
        // Act
        // Assert
        Assert.Equal(1, num);
        Assert.True(fast);
    }
}