简体   繁体   English

如何在xunit / autofixture中组合PropertyData和AutoNSubstituteData属性?

[英]How to combine PropertyData and AutoNSubstituteData attributes in xunit/autofixture?

I am using the [AutoNSubstituteData] attribute, which was posted here: 我正在使用[AutoNSubstituteData]属性,该属性已在此处发布:

AutoFixture, xUnit.net, and Auto Mocking AutoFixture,xUnit.net和Auto Mocking

I would like to combine this with the [PropertyData("")] attribute from xunit extensions. 我想将它与xunit扩展的[PropertyData("")]属性结合起来。

This is my test: 这是我的测试:

public static IEnumerable<string[]> InvalidInvariant
{
    get
    {
        yield return new string[] { null };
        yield return new [] { string.Empty };
        yield return new [] { " " };
    }
}

[Theory, AutoNSubstituteData, PropertyData("InvalidInvariant")]
public void TestThatGuardsAreTriggeredWhenConnectionStringArgumentIsInvalid(
    IDeal deal,
    IDbConnection conn,
    IDb db,
    ISender sender,
    string invalidConnString,
    string query)
{
    deal.Init.Group.Returns(Group.A);
    deal.Aggr.Group.Returns(Group.A);
    deal.Product.Commodity.Returns(Product.Commodity.E);

    var sut = new Handler(db, sender);
    Assert.Throws<ArgumentException>(() => 
        sut.HandleDeal(deal, conn, invalidConnString, query));
}

Is there a way to combine these attributes or to get the desired functionality (mock everything, except for invalidConnstring , which should be filled with the property-data)? 有没有办法组合这些属性或获得所需的功能(模拟一切,除了invalidConnstring ,应该用属性数据填充)?

The [Theory] attribute works by looking for one or more 'data source attributes'; [Theory]属性通过查找一个或多个'数据源属性'来工作; for example 例如

  • [InlineData]
  • [PropertyData]
  • [ClassData]
  • etc. 等等

The [AutoData] attribute is just another such attribute, as is your derived [AutoNSubstituteData] attribute. [AutoData]属性只是另一个这样的属性,派生的[AutoNSubstituteData]属性也是如此。

It's possible to add more than one 'data source attribute' to the same [Theory] , as witnessed by the idiomatic use of the [InlineData] attribute: 可以将相同的[Theory]添加多个“数据源属性”,这可以通过[InlineData]属性的惯用使用来[InlineData]

[Theory]
[InlineData("foo")]
[InlineData("bar")]
[InlineData("baz")]
public void MyTest(string text)

This produces three test cases. 这产生了三个测试用例。

It's also possible to combine [PropertyData] and [AutoData] , but it probably doesn't do what you want it to do . 也可以组合[PropertyData][AutoData] ,但它可能不会做你想做的事情 This: 这个:

[Theory]
[AutoNSubstituteData]
[PropertyData("InvalidInvariant")]
public void MyTest(/* parameters go here */)

will result in 1 + n test cases: 将导致1 + n个测试用例:

  • 1 test case from [AutoNSubstituteData] 来自[AutoNSubstituteData] 1个测试用例
  • n test cases from the InvalidInvariant property 来自InvalidInvariant属性的n个测试用例

These two attributes know nothing about each other, so you can't combine them in the sense that they're aware of each other. 这两个属性对彼此一无所知,所以你不能将它们组合起来,因为它们彼此了解。

However, when you're implementing a property, you can write whatever code you'd like, including using a Fixture instance, so why not just do this? 但是,当您实现一个属性时,您可以编写您想要的任何代码,包括使用Fixture实例,那么为什么不这样做呢?

public static IEnumerable<string[]> InvalidInvariant
{
    get
    {
        var fixture = new Fixture().Customize(new MyConventions());
        // use fixture to yield values...,
        // using the occasional hard-coded test value
    }
}

Another option is to use derive from the InlineAutoDataAttribute , which would enable you to write your test cases like this: 另一种选择是使用来自InlineAutoDataAttribute派生,这将使您能够像这样编写测试用例:

[Theory]
[MyInlineAutoData("foo")]
[MyInlineAutoData("bar")]
[MyInlineAutoData("baz")]
public void MyTest(string text, string someOtherText, int number, Guid id)

This would cause the first argument ( text ) to be populated with the constants from the attributes, while the remaining parameters are populated by AutoFixture. 这将导致第一个参数( text )用属性中的常量填充,而其余参数由AutoFixture填充。

Theoretically, you may also be able to combine the [AutoData] and [PropertyData] attributes using the CompositeDataAttribute , but it may not work the way you'd like . 从理论上讲,您也可以使用CompositeDataAttribute [AutoData][PropertyData]属性,但它可能无法按照您的喜好工作

Finally, you could consider using Exude for true first-class parameterized tests. 最后,您可以考虑使用Exude进行真正的一流参数化测试。

There are two ways to do this: 有两种方法可以做到这一点:

Option 1 - Using AutoFixture.Xunit and the CompositeDataAttribute class: 选项1 - 使用AutoFixture.Xunit和CompositeDataAttribute类:

internal class AutoNSubstituteDataAttribute : AutoDataAttribute
{
    internal AutoNSubstituteDataAttribute()
        : base(new Fixture().Customize(new AutoNSubstituteCustomization()))
    {
    }
}

internal class AutoNSubstitutePropertyDataAttribute : CompositeDataAttribute
{
    internal AutoNSubstitutePropertyDataAttribute(string propertyName)
        : base(
            new DataAttribute[] { 
                new PropertyDataAttribute(propertyName), 
                new AutoNSubstituteDataAttribute() })
    {
    }
}

Define the test cases as below: 定义测试用例如下:

public class Scenario
{
    public static IEnumerable<object[]> InvalidInvariantCase1
    {
        get
        {
            yield return new string[] { null };
        }
    }

    public static IEnumerable<object[]> InvalidInvariantCase2
    {
        get
        {
            yield return new string[] { string.Empty };
        }
    }

    public static IEnumerable<object[]> InvalidInvariantCase3
    {
        get
        {
            yield return new string[] { " " };
        }
    }
}

Then declare the parameterized test as: 然后将参数化测试声明为:

public class Scenarios
{
    [Theory]
    [AutoNSubstitutePropertyData("InvalidInvariantCase1")]
    [AutoNSubstitutePropertyData("InvalidInvariantCase2")]
    [AutoNSubstitutePropertyData("InvalidInvariantCase3")]
    public void AParameterizedTest(
        string invalidConnString,
        IDeal deal,
        IDbConnection conn,
        IDb db,
        ISender sender,
        string query)
    {
    }
}

Please note that the parameterized parameter invalidConnString have to be declared before the other parameters . 请注意,参数化参数invalidConnString必须在其他参数之前声明

Option 2 - Using Exude : 选项2 - 使用Exude

public class Scenario
{
    public void AParameterizedTest(
        IDeal deal,
        IDbConnection conn,
        IDb db,
        ISender sender,
        string invalidConnString,
        string query)
    {
    }

    [FirstClassTests]
    public static TestCase<Scenario>[] RunAParameterizedTest()
    {
        var testCases = new [] 
        {
            new 
            {
                invalidConnString = (string)null
            },
            new
            {
                invalidConnString = string.Empty
            },
            new
            {
                invalidConnString = " "
            }
        };

        var fixture = new Fixture()
            .Customize(new AutoNSubstituteCustomization());

        return testCases
            .Select(tc =>
                new TestCase<Scenario>(
                    s => s.AParameterizedTest(
                        fixture.Create<IDeal>(),
                        fixture.Create<IDbConnection>(),
                        fixture.Create<IDb>(),
                        fixture.Create<ISender>(),
                        tc.invalidConnString,
                        fixture.Create<string>())))
            .ToArray();
    }
}

I have implemented an AutoPropertyDataAttribute that combines xUnit's PropertyDataAttribute with AutoFixture's AutoDataAttribute . 我已经实现了一个AutoPropertyDataAttribute ,它将xUnit的PropertyDataAttribute与AutoFixture的AutoDataAttribute相结合。 I posted it as an answer here . 我在这里发布了答案。

In your case you will need to inherit from the attribute in the same way as you would from an AutoDataAttribute , with the exception that you pass a fixture creation function instead of an instance: 在您的情况下,您将需要以与从AutoDataAttribute相同的方式继承属性,除了您传递夹具创建函数而不是实例:

public class AutoNSubPropertyDataAttribute : AutoPropertyDataAttribute
{
    public AutoNSubPropertyDataAttribute(string propertyName)
        : base(propertyName, () => new Fixture().Customize(new AutoNSubstituteCustomization()))
    {
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM