📊 Data-Driven Testing
Prova supports powerful data-driven testing using [Theory] combined with various data source attributes. This allows you to run the same test logic multiple times with different inputs.
📥 Inline Data
The simplest way to provide data is using [InlineData].
using Prova;
public class MyTests
{
[Theory]
[InlineData(1, 1, 2)]
[InlineData(10, 20, 30)]
public void AddTest(int a, int b, int expected)
{
Assert.Equal(expected, a + b);
}
}🏗️ Class Data
For complex data or data that needs to be shared across multiple test classes, use [ClassData]. The specified class must implement IEnumerable<object[]>.
public class MyTestData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { 1, "One" };
yield return new object[] { 2, "Two" };
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
[Theory]
[ClassData(typeof(MyTestData))]
public void SharedDataTest(int id, string name) { ... }🔗 Member Data
Use [MemberData] to source data from a static property, method, or field. This is highly flexible and supports parameters for methods.
Static Property
public static IEnumerable<object[]> PropertyData => new[]
{
new object[] { 1 },
new object[] { 2 }
};
[Theory]
[MemberData(nameof(PropertyData))]
public void PropertyTest(int x) { ... }Static Method with Parameters
public static IEnumerable<object[]> GetMethodData(int count)
{
for (int i = 0; i < count; i++) yield return new object[] { i };
}
[Theory]
[MemberData(nameof(GetMethodData), 3)]
public void MethodTest(int x) { ... }External Member
You can also source data from a member in a different class using the MemberType property.
[Theory]
[MemberData(nameof(ExternalSource.Data), MemberType = typeof(ExternalSource))]
public void ExternalTest(int x) { ... }🏢 Class-Level Data (Constructor Parameterization)
Prova allows you to apply [InlineData], [MemberData], or [ClassData] directly to a test class. When done, every test in the class will be executed for each row of data provided, and the data will be injected into the class constructor.
This is extremely useful for testing a component with multiple configurations (e.g., different storage providers, different mock settings).
[InlineData("StorageA", 1024)]
[InlineData("StorageB", 2048)]
public class StorageTests
{
private readonly string _name;
private readonly int _limit;
public StorageTests(string name, int limit)
{
_name = name;
_limit = limit;
}
[Fact]
public void VerifyLimit()
{
Assert.Equal(_limit, GetStorage(_name).Capacity);
}
}TIP
You can combine Class-Level Data with Method-Level Theories. If a class has 2 data rows and a method has 3 data rows, the method will run a total of 6 times (2 * 3).
🚀 Performance Note
Because Prova is a source-generated runner, all data-driven tests are expanded at compile-time into individual test registrations (when possible) or iterated at runtime using the generated loops. This ensures maximum performance and full AOT compatibility.