在XUnit测试中使用AutoData和MemberData属性

Seb*_*Seb 10 unit-testing xunit autofixture

我正面临一个有趣的问题.我发现AutoDataAttribute可用于最小化测试的"排列"部分(通过ctor传递的依赖关系).真棒!

例:

public class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute()
        : base(new Fixture().Customize(new AutoMoqCustomization()))
    { }
}

[Theory, AutoMoqData]
public void Process_ValidContext_CallsK2Workflows(
    [Frozen]Mock<IK2Datasource> k2,
    [Frozen]Mock<IAppConfiguration> config,
    PrBatchApproveBroker sut)
{
   (...)
}
Run Code Online (Sandbox Code Playgroud)

现在我想使用这个伟大的功能,并将自己的数据注入到这个理论中:

[Theory, AutoMoqData, MemberData("Data")]
public void ExtractPayments_EmptyInvoiceNumber_IgnoresRecordsWithEmptyInvoiceNumber(
        [Frozen]Mock<IExcelDatasource> xls,
        SunSystemExcelDatasource sut,
        List<Row> rows,
        int expectedCount)
{
    (...)
}
Run Code Online (Sandbox Code Playgroud)

问题:AutoData属性将为我生成随机数据.我发现的唯一方法是摆脱AutoData属性并使用MemberData.如果我这样做,我需要自己处理对象实例化:))...

有没有办法同时传递我的类一些"硬编码"数据?

谢谢你,Seb

Nik*_*nis 7

有没有办法同时传递我的类一些"硬编码"数据?

一种方法是通过属性提供一些内联值,并让AutoFixture填充其余的内容.

[Theory, InlineAutoMoqData(3)]
public void ExtractPayments_EmptyInvoiceNumber_IgnoresRecordsWithEmptyInvoiceNumber(
    int expectedCount,
    [Frozen]Mock<IExcelDatasource> xls,
    SunSystemExcelDatasource sut,
    List<Row> rows)
{
    // expectedCount is 3.
}
Run Code Online (Sandbox Code Playgroud)

请注意,我必须移动expectedCount才能成为第一个参数,并使用InlineAutoMoqData定义为的自定义属性:

internal class AutoMoqDataAttribute : AutoDataAttribute
{
    internal AutoMoqDataAttribute()
        : base(new Fixture().Customize(new AutoMoqCustomization()))
    {
    }
}

internal class InlineAutoMoqDataAttribute : CompositeDataAttribute
{
    internal InlineAutoMoqDataAttribute(params object[] values)
        : base(
              new DataAttribute[] { 
                  new InlineDataAttribute(values),
                  new AutoMoqDataAttribute() })
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

又见这个职位和一个对其他一些例子.


Kir*_*lly 5

您必须创建自己的自定义 DataAttribute。这就是你可以作曲的方式。

/// <summary>
/// Helper DataAttribute to use the regular xUnit based DataAttributes with AutoFixture and Mocking capabilities.
/// </summary>
/// <seealso cref="Xunit.Sdk.DataAttribute" />
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class AutoCompositeDataAttribute : DataAttribute
{
    /// <summary>
    /// The attributes
    /// </summary>
    private readonly DataAttribute baseAttribute;

    /// <summary>
    /// The automatic data attribute
    /// </summary>
    private readonly DataAttribute autoDataAttribute;

    /// <summary>
    /// Initializes a new instance of the <see cref="AutoCompositeDataAttribute" /> class.
    /// </summary>
    /// <param name="baseAttribute">The base attribute.</param>
    /// <param name="autoDataAttribute">The automatic data attribute.</param>
    public AutoCompositeDataAttribute(DataAttribute baseAttribute, DataAttribute autoDataAttribute)
    {
        this.baseAttribute = baseAttribute;
        this.autoDataAttribute = autoDataAttribute;
    }

    /// <summary>
    /// Returns the data to be used to test the theory.
    /// </summary>
    /// <param name="testMethod">The method that is being tested</param>
    /// <returns>
    /// One or more sets of theory data. Each invocation of the test method
    /// is represented by a single object array.
    /// </returns>
    public override IEnumerable<object[]> GetData(MethodInfo testMethod)
    {
        if (testMethod == null)
        {
            throw new ArgumentNullException(nameof(testMethod));
        }

        var data = this.baseAttribute.GetData(testMethod);

        foreach (var datum in data)
        {
            var autoData = this.autoDataAttribute.GetData(testMethod).ToArray()[0];

            for (var i = 0; i < datum.Length; i++)
            {
                autoData[i] = datum[i];
            }

            yield return autoData;
        }
    }
}



/// <summary>
/// Member auto data implementation based on InlineAutoDataAttribute and MemberData
/// </summary>
/// <seealso cref="Ploeh.AutoFixture.Xunit2.CompositeDataAttribute" />
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class MemberAutoDataAttribute : AutoCompositeDataAttribute
{
    /// <summary>
    /// The automatic data attribute
    /// </summary>
    private readonly AutoDataAttribute autoDataAttribute;

    /// <summary>
    /// Initializes a new instance of the <see cref="MemberAutoDataAttribute" /> class.
    /// </summary>
    /// <param name="memberName">Name of the member.</param>
    /// <param name="parameters">The parameters.</param>
    public MemberAutoDataAttribute(string memberName, params object[] parameters)
        : this(new AutoDataAttribute(), memberName, parameters)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="MemberAutoDataAttribute" /> class.
    /// </summary>
    /// <param name="autoDataAttribute">The automatic data attribute.</param>
    /// <param name="memberName">Name of the member.</param>
    /// <param name="parameters">The parameters.</param>
    public MemberAutoDataAttribute(AutoDataAttribute autoDataAttribute, string memberName, params object[] parameters)
        : base((DataAttribute)new MemberDataAttribute(memberName, parameters), (DataAttribute)autoDataAttribute)
    {
        this.autoDataAttribute = autoDataAttribute;
    }

    /// <summary>
    /// Gets the automatic data attribute.
    /// </summary>
    /// <value>
    /// The automatic data attribute.
    /// </value>
    public AutoDataAttribute AutoDataAttribute => this.autoDataAttribute;
}
Run Code Online (Sandbox Code Playgroud)

如果你想启用 Moq,那么扩展它以获得

/// <summary>
/// The member auto moq data attribute.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class MemberAutoMoqDataAttribute : MemberAutoDataAttribute
{
    /// <summary>
    /// Initializes a new instance of the <see cref="MemberAutoMoqDataAttribute"/> class.
    /// </summary>
    /// <param name="memberName">Name of the member.</param>
    /// <param name="parameters">The parameters.</param>
    public MemberAutoMoqDataAttribute(string memberName, params object[] parameters)
        : base(new AutoMoqDataAttribute(), memberName, parameters)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)