I am using the [AutoNSubstituteData]
attribute, which was posted here:
AutoFixture, xUnit.net, and Auto Mocking
I would like to combine this with the [PropertyData("")]
attribute from xunit extensions.
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)?
There are two ways to do this:
Option 1 - Using AutoFixture.Xunit and the CompositeDataAttribute class:
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.
Option 2 - Using 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();
}
}
The [Theory]
attribute works by looking for one or more 'data source attributes'; for example
[InlineData]
[PropertyData]
[ClassData]
The [AutoData]
attribute is just another such attribute, as is your derived [AutoNSubstituteData]
attribute.
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("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. This:
[Theory]
[AutoNSubstituteData]
[PropertyData("InvalidInvariant")]
public void MyTest(/* parameters go here */)
will result in 1 + n test cases:
[AutoNSubstituteData]
InvalidInvariant
propertyThese 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?
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:
[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.
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.
Finally, you could consider using Exude for true first-class parameterized tests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With