The third data feeds three more sets of data to the test method. However, that data originates from the GetData method of the ExternalData class, sending 10 as an argument during the execution (the start parameter). To do that, we must specify the MemberType instance where the method is located so xUnit knows where to look. In this case, we pass the argument 10 as the second parameter of the MemberData constructor. However, in other cases, you can pass zero or more arguments there.Finally, we are doing the same for the ExternalData.TypedData property, which is represented by the [MemberData(nameof(ExternalData.TypedData), MemberType = typeof(ExternalData))] attribute. Once again, the only difference is that the property is defined using TheoryData instead of IEnumerable<object[]>, which makes its intent clearer.When running the tests, the data provided by the [MemberData] attributes are combined, yielding the following result in the Test Explorer:

Figure 2.5: Member data theory test results
These are only a few examples of what we can do with the [MemberData] attribute.
I understand that’s a lot of condensed information, but the goal is to cover just enough to get you started. I don’t expect you to become an expert in xUnit by reading this chapter.
Last but not least, the [ClassData] attribute gets its data from a class implementing IEnumerable<object[]> or inheriting from TheoryData<…>. The concept is the same as the other two. Here is an example:
public class ClassDataTest
{
[Theory]
[ClassData(typeof(TheoryDataClass))]
[ClassData(typeof(TheoryTypedDataClass))]
public void Should_be_equal(int value1, int value2, bool shouldBeEqual)
{
if (shouldBeEqual)
{
Assert.Equal(value1, value2);
}
else
{
Assert.NotEqual(value1, value2);
}
}
public class TheoryDataClass : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { 1, 2, false };
yield return new object[] { 2, 2, true };
yield return new object[] { 3, 3, true };
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class TheoryTypedDataClass : TheoryData<int, int, bool>
{
public TheoryTypedDataClass()
{
Add(102, 104, false);
}
}
}
These are very similar to [MemberData], but we point to a type instead of pointing to a member.In TheoryDataClass, implementing the IEnumerable<object[]> interface makes it easy to yield return the results. On the other hand, in the TheoryTypedDataClass class, by inheriting TheoryData, we can leverage a list-like Add method. Once again, I find inheriting from TheoryData more explicit, but either way works with xUnit. You have many options, so choose the best one for your use case.Here is the result in the Test Explorer, which is very similar to the other attributes:

Figure 2.6: Test Explorer
That’s it for the theories—next, a few last words before organizing our tests.