2016-06-29 5 views
4

У меня возникла интересная проблема. Я узнал, что AutoDataAttribute может использоваться для минимизации части «Упорядочить» вашего теста (зависимости, переданные через ctor). Потрясающие!Использовать атрибуты AutoData и MemberData в тесте XUnit

Пример:

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. Если я сделаю это, мне нужно обрабатывать объект Instantiations себе:) ...

Есть ли способ передать свои классы и некоторых «жестко закодированные» данных в то же время?

Спасибо и, Себа

ответ

4

Есть ли способ передать свои классы и некоторых «жестко закодированные» данных в то же время?

Один из способов сделать это, предоставив некоторые встроенные значения через атрибут и заполнив оставшуюся часть 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 один за другой Примеры.

+0

Выглядит хорошо. Может ли он быть составлен с помощью 'MemberData'? –

+0

Не знаю. Из того, что я вижу [здесь] (https://xunit.github.io/docs/test-migration.html), 'MemberData' подобен' PropertyData', но также поддерживает статические поля и статические методы. –

+1

В [this] (http://stackoverflow.com/a/22996375/467754) answer, 'PropertyData' объединен с' AutoNSubstituteData', поэтому он должен * работать в xUnit.net 2.x с 'MemberData' как Что ж... –

0

Вам нужно будет создать свой собственный атрибут 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; 
} 

Если вы хотите включить 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) 
    { 
    } 
}