NUnit has long supported the definition of test cases in numerous forms, including via inline primitive data via the TestCaseAttribute or potentially more complex data returned from a method, property, or other source at runtime via TestCaseSourceAttribute. The latter has typically only supported synchronous methods. This complicated defining data-driven test cases where an internal operation required calling a Task-based API. A common example of this could be a test case which reads from a JSON source file or other stream using a method like JsonSerializer.DeserializeAsync().
In the past this would mean an awkward and unnatural call using something like .GetAwaiter().GetResult():
public class Tests
{
[TestCaseSource(nameof(MyMethod))]
public void Test1(MyClass item)
{
}
public static IEnumerable<MyClass> MyMethod()
{
using var file = File.OpenRead("Path/To/data.json");
var t = JsonSerializer.DeserializeAsync<IEnumerable<MyClass>>(file).AsTask();
return t.GetAwaiter().GetResult();
}
}
NUnit 3.14 was released a few months ago and included support for “async” or task-based test case sources. Now a TestCaseSource can target a Task-returning method to allow for much more natural code:
public class Tests
{
[TestCaseSource(nameof(MyMethodAsync))]
public void Test1Async(MyClass item)
{
}
public static async Task<IEnumerable<MyClass>> MyMethodAsync()
{
using var file = File.OpenRead("Path/To/data.json");
return await JsonSerializer.DeserializeAsync<IEnumerable<MyClass>>(file);
}
}
The above example focuses on Task, but any awaitable type such as ValueTask or a custom awaitable also works. Other “source” attributes such as TestFixtureSource or ValueSource are supported as well.

Leave a Reply