Skip to main content

Dynamically Created Tests

TUnit offers the ability to create your tests via dynamic code, as opposed to the standard [Test] attribute and data attributes.

To do this, create a new class with a public parameterless constructor.

Then, create a public method, called whatever you like, with a single parameter of DynamicTestBuilderContext, and place the [DynamicTestBuilder] attribute on that method.

On the context parameter, you can call .AddTest(...), and pass it a new DynamicTest<T>.

T is the class containing the method you want to invoke. If your class contains parameters or properties, or your method contains parameters, you can pass these into the test parameter

For simple tests, there is not much point using this feature. But it may be helpful when wanting to generate lots of test cases with different data.

Here's an example:

namespace TUnit.TestProject.DynamicTests;

public class Basic
{
public void SomeMethod()
{
Console.WriteLine(@"Hello, World!");
}

[DynamicTestBuilder]
public void BuildTests(DynamicTestBuilderContext context)
{
context.AddTest(new DynamicTest<Basic>
{
TestMethod = @class => @class.SomeMethod(),
TestMethodArguments = [],
Attributes = [new RepeatAttribute(5)]
});
}
}

It is also possible to build a test from within another test:

[RunOnDiscovery]
[Arguments(1, 2, 3)]
[Arguments(101, 202, 303)]
public class Runtime(int a, int b, int c)
{
public void SomeMethod(int arg1, int arg2, int arg3)
{
Console.WriteLine(@"SomeMethod called with:");
Console.WriteLine($@"Class args: {a}, {b}, {c}");
Console.WriteLine($@"Method args: {arg1}, {arg2}, {arg3}");
}

[Test]
[Arguments(4, 5, 6)]
[Arguments(404, 505, 606)]
public async Task BuildTests(int d, int e, int f)
{
var context = TestContext.Current!;

await context.AddDynamicTest(new DynamicTest<Runtime>
{
TestMethod = @class => @class.SomeMethod(0, 0, 0),
TestClassArguments = [a + 10, b + 10, c + 10],
TestMethodArguments = [d + 10, e + 10, f + 10],
Attributes = [new RepeatAttribute(5)]
});
}
}