Data Driven Async Tests in Unity with UnityTest & UniTask

UniTask enables us to cleanly use async/await syntax within Unity. Testing code that uses UniTask requires that we use Unity Test Framework and run the tests from within a [UnityTest]. The recommended syntax for this is:

[UnityTest]
public IEnumerator MyFunctionDoesWhatIExpect() => UniTask.ToCoroutine(async () =>
{
    MyType result = await SomeFunctionThatReturnsAUniTask();
    result.SomeProperty.Should().Be(theValueIExpect); // yay FluentAssertions!
});

But what if we want to run the same test with different input parameters? We don’t want to just duplicate the same code in every test; that would be a maintenance nightmare. NUnit solves this nicely with the [TestCase] attribute.

Unity Test Framework’s [UnityTest] attribute does not support an equivalent to NUnit’s [TestCase] attribute for parameterized tests.

But, it does support the [ValueSource] attribute. While not nearly as clean, we can get some basic parameterized testing using something like this:

private static readonly (string input, string expectedOutput)[] InputsAndExpectedOutputs =
{
    (null,""),
    ("a name", "a name"),
    ("remove special characters !@#$%^&*()[]", "remove special characters"),
};

[UnityTest]
public IEnumerator MyStringFunctionDoesWhatIExpect(
[ValueSource(nameof(InputsAndExpectedOutputs))](string input, string expectedOutput) ioPair
) => UniTask.ToCoroutine(async () =>
{
    var result = await MyUniTaskStringFunction(ioPair.input);
    result.Should().BeEquivalentTo(ioPair.expectedOutput);
});

It’s pretty ugly, but it works!

For more information on what you can do with [ValueSource], check out this tutorial