This section will cover [TestCase]
and similar NUnit attributes and how to work with them in UnityTests.
NUnit has a few tools for parameterized tests, which can be used to specify test cases with variating parameters. This can drastically reduce the amount of repeated code and make the test cleaner to use.
An example of a parameterized test using the [TestCase]
attribute:
[Test]
[TestCase(49, "a string", true)]
[TestCase(9, "something", false)]
public void MyTest(int firstValue, string secondValue, bool expectedOutcome)
{
...
}
This will generate two tests, each with a different input to the method body.
In addition to the [TestCase]
attribute, NUnit also has a [Values]
attribute, which specifies a set of values on each individual input. An example of such is:
[Test]
public void MyTest([Values(49, 9)]int firstValue, [Values("a string", "something")]string secondValue)
{
...
}
When specifying multiple input parameters, they are treated as combinatorial. That means that each combination of them will be tested. For the above example, that will result in a total of 4 cases:
MyTest(49, "a string")
MyTest(49, "something")
MyTest(9, "a string")
MyTest(9, "something")
This can easily explode into many combinations. The combinations might not all be valuable and would just waste time, so use this with care.
For both the [TestCase]
and [Values]
attributes, there is a more dynamic version called [TestCaseSource]
and [ValueSource]
accordingly. These each take in a static method or array, returning a collection of objects.
Of these 4 methods, the [ValueSource]
attribute is currently the only one supported by [UnityTest]
. Since this would produce combinational tests, if multiple arguments with [ValueSource]
are provided, then it is recommended to make a test case struct, if multiple arguments are needed for the test. An example of such could look like this:
[UnityTest]
public IEnumerator AddAsyncCalculatesCorrectValue([ValueSource(nameof(TestCases))] TestCase testCase)
{
...
}
private static IEnumerable TestCases()
{
yield return new TestCase {value1 = 4, value2 = "a string"};
yield return new TestCase {value1 = 8, value2 = "another string"};
}
public struct TestCase
{
public int value1;
public string value2;
public override string ToString()
{
return $"{value1}, {value2}";
}
}
In the sample 15_TestCases
a class is set up with some basic math. It has two methods:
Add
which takes two integers and adds them together.
AddAsync
also adds two integers together, but does so asynchronously, yielding back an IEnumerator
The task is to add tests for the two methods. The AddAsync
method first returns the result after a few frames, so that will be best suited for a [UnityTest]
. Note that it is not enough to yield back the IEnumerator
, as the test framework does not curently support nested yields. Instead, create a loop to move over each element until it’s done. At each step of the while loop, let the test yield back null.
ToString()
implementation in the struct is there to provide readable info in the test runnerThe Test Framework package (formerly called the Test Runner) is a Unity tool that tests your code in both Edit mode and Play mode, and also on target platforms such as Standalone, Android, or iOS. More infoA solution for the exercise is available in the sample 15_TestCases_Solution
. Tests for both methods can be implemented as follows:
[Test]
[TestCase(24, 80, 104)]
[TestCase(10, -15, -5)]
[TestCase(int.MaxValue, 10, int.MinValue + 9)]
public void AddCalculatesCorrectValue(int valueA, int valueB, int expectedResult)
{
var myClass = new MyClass();
var result = myClass.Add(valueA, valueB);
Assert.That(result, Is.EqualTo(expectedResult));
}
[UnityTest]
public IEnumerator AddAsyncCalculatesCorrectValue([ValueSource(nameof(AdditionCases))] AddCase addCase)
{
var myClass = new MyClass();
var enumerator = myClass.AddAsync(addCase.valueA, addCase.valueB);
while (enumerator.MoveNext())
{
yield return null;
}
var result = enumerator.Current;
Assert.That(result, Is.EqualTo(addCase.expectedResult));
}
private static IEnumerable AdditionCases()
{
yield return new AddCase {valueA = 24, valueB = 80, expectedResult = 104};
yield return new AddCase {valueA = 10, valueB = -15, expectedResult = -5};
yield return new AddCase {valueA = int.MaxValue, valueB = 10, expectedResult = int.MinValue + 9};
}
public struct AddCase
{
public int valueA;
public int valueB;
public int expectedResult;
public override string ToString()
{
return $"{valueA} + {valueB} = {expectedResult}";
}
}
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.