【问题标题】:Use AutoData and MemberData attributes in XUnit test在 XUnit 测试中使用 AutoData 和 MemberData 属性
【发布时间】:2016-06-29 01:00:46
【问题描述】:

我遇到了一个有趣的问题。我发现 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)
{
   (...)
}

现在我想使用这个很棒的功能将我自己的数据注入到这个理论中:

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

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

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

谢谢你, 赛博

【问题讨论】:

    标签: unit-testing xunit autofixture


    【解决方案1】:

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

    一种方法是通过属性提供一些内联值,并让 AutoFixture 填充其余部分。

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

    请注意,我必须移动 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() })
        {
        }
    }
    

    另请参阅this 帖子和this 其他一些示例。

    【讨论】:

    • 我不知道。从我看到的hereMemberData 就像PropertyData 一样,但它也支持静态字段和静态方法。
    • this 答案中,PropertyDataAutoNSubstituteData 结合使用,因此它应该在 xUnit.net 2.x 中与MemberData 一起工作。 .
    【解决方案2】:

    您必须创建自己的自定义 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;
    }
    

    如果你想启用起订量,那么扩展它以获得

    /// <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)
        {
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-31
      • 2018-06-20
      • 1970-01-01
      • 2018-10-14
      • 2018-01-26
      相关资源
      最近更新 更多