how should I write a test involving an external API call using the Unity3d test runner? I am unable to find a way to make the test runner await a callback. Take a look at this simplified example:
[Test]
public void TestingAsyncCall()
{
var result = false;
new WWWApiCall(_ =>
{
result = true;
});
Assert.AreEqual(true, result);
}
The assert fails, result is still false but ought to be true…
If you are on Unity 2017.1, you can use the new test infrastructure, and specifically the UnityTest attribute.
This attribute allows you to declare and execute your test as a coroutine.
You could write the test in your example similar to this:
[UnityTest]
public IEnumerator TestingAsyncCall()
{
var timeout = 5f; // timeout after 5 seconds
var result = false;
new WWWApiCall(_ =>
{
result = true;
});
yield return new WaitForSeconds(timeout);
Assert.AreEqual(true, result);
}
Not the best implementation as it will always wait for the timeout before asserting, but you can enhance it if you like.
Hi, thanks for the answer. I actually already tested it, but it does not work. And even if it did work, the hack is just way too ugly, and it locks you to using the rigid UnityTest instead of the regular nunit Test.
Here is a complete example that illustrates how testing async is not working and so far seems impossible in Unity.
[UnityTest]
public IEnumerator TestingAsyncCall()
{
var result = false;
Task.Run(() =>
{
result = true;
});
yield return new WaitForSeconds(1);
Assert.AreEqual(true, result);
}
Leads to: Unhandled log message: [Error] EditMode test can only yield null.
I can change it to yield return null, but then the wait time needed for an async web api call is not going to be suficcient.
async testing is possible. it doesn’t “lock” you to anything. nunit tests are not async. they are triggered and completed, and cannot wait for any async operation to complete.
The UnityTest attribute solves this by executing your test as a coroutine.
The error you’re getting means that you placed your test in an Editor folder. move it into another folder (e.g: non editor) and it should work.
The error log tells you UnityTests can not yield return anything other than null, in EditMode.
Either you can make it a runtime test by moving your test code to a file not in an editor folder,
or you can work around the “yield return new WaitForSeconds(1)”.
public IEnumerator TestingAsyncCall()
{
var result = false;
Task.Run(() =>
{
result = true;
});
DateTime startTime = DateTime.UtcNow;
do
{
yield return null;
}
while ((DateTime.UtcNow - startTime).TotalSeconds < 1.0);
Assert.AreEqual(true, result);
}