Using xUnit.net, it is possible for a Theory
to have its MemberData
originate from a derived class?
public abstract class BaseTest
{
public abstract IEnumerable<object[]> Data();
[Theory]
[MemberData(nameof(Data))]
public void TestData(string expected, string actual)
{
// assert goes here
}
}
public class ComplexTest : BaseTest
{
public override IEnumerable<object[]> Data()
{
// data goes here
}
}
The code above results in the following error message:
System.NotSupportedException : Specified method is not supported.
Another way of doing this (and IMO cleaner), is to put your test scenarios in their own specific classes and just define each scenario set as a separate MemberData attribute:
public class BaseTest
{
[Theory]
[MemberData(nameof(TestScenarios1.Data), MemberType = typeof(TestScenarios1)]
[MemberData(nameof(TestScenarios1.MoreData), MemberType = typeof(TestScenarios1)]
[MemberData(nameof(TestScenarios2.DifferentData), MemberType = typeof(TestScenarios2)]
public void TestData(string expected, string actual)
{
// assert goes here
}
}
public class TestScenarios1
{
public static IEnumerable<object[]> Data()
{
// data goes here
}
public static IEnumerable<object[]> MoreData()
{
// data goes here
}
}
public class TestScenarios2
{
public static IEnumerable<object[]> DifferentData()
{
// data goes here
}
}
As far as I know, this is not possible. MemberData
's data is required to be static
, therefore the data must originate from its own class.
public static IEnumerable<object[]> Data()
{
// data goes here
}
[Theory]
[MemberData(nameof(Data))]
public void TestData(string expected, string actual)
{
// assert goes here
}
You're correct in your answer. Posting this non-answer in case it happens to spark an idea.
MemberData
can be passed params, which might help depending on your specific scenario?
Other than that, the best you can prob do is to put a forwarder:
public abstract class BaseTest
{
protected void RunTest(string expected, string actual)
{
Assert.Equal(expected, actual);
}
}
public class ComplexTest : BaseTest
{
static IEnumerable<object[]> Data() =
{
{ "a", "a" }
}
[Theory, MemberData(nameof(Data))]
void TestData(expected, actual) => base.RunTest(expected, actual);
}
Another way is to add MemberData only to derived class. It will check members by name and take the correct one from the current class. The only thing that analyzer with warn that you must specify member in base class (that by default treated as an error), so you have to disable this rule. If you try to specify this method in both classes - base and derived only base classes would be used. The issue about analyzer described in xunit github: https://github.com/xunit/xunit/issues/1243
Your example may look:
public abstract class BaseTest
{
[Theory]
#pragma warning disable xUnit1015 // MemberData must reference an existing member
[MemberData(nameof(Data))]
#pragma warning restore xUnit1015 // MemberData must reference an existing member
public void TestData(string expected, string actual)
{
// assert goes here
}
}
public class ComplexTest : BaseTest
{
public static IEnumerable<object[]> Data()
{
return data;
// data goes here
}
}
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