My goal is to implement a test, that can check if an error is logged, when it is happened in the async void
method.
I have this sample class for editor mode auto-testing in Unity3d:
public class AsyncLogTest
{
[Test]
public void Test1()
{
ThrowException();
LogAssert.Expect(LogType.Exception, new Regex(".*"));
}
[Test]
public void Test2()
{
DirectLog();
LogAssert.Expect(LogType.Exception, new Regex(".*"));
}
[UnityTest]
public IEnumerator Test3()
{
LogAssert.ignoreFailingMessages = true;
ThrowException();
yield return null;
LogAssert.Expect(LogType.Exception, new Regex(".*"));
}
[UnityTest]
public IEnumerator Test4()
{
ThrowException();
// Wait for 1 second
var stopwatch = new Stopwatch();
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds < 1000)
{
yield return null;
}
stopwatch.Stop();
LogAssert.Expect(LogType.Exception, new Regex(".*"));
}
[UnityTest]
public IEnumerator Test5()
{
LogAssert.ignoreFailingMessages = true;
ThrowException();
// Wait for 1 second
var stopwatch = new Stopwatch();
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds < 1000)
{
yield return null;
}
stopwatch.Stop();
LogAssert.Expect(LogType.Exception, new Regex(".*"));
}
public async void ThrowException()
{
throw new Exception();
}
public async void DirectLog()
{
Debug.LogException(new Exception());
}
}
The result of this tests is next:
- Test1 - always fails due to
Expected log did not appear: [Exception] Regex: .*.
- Test2 - always success.
- Test3 - sometimes fails, sometimes success. Fail reason -
Expected log did not appear: [Exception] Regex: .*
- Test4 - always fails due to
Unhandled log message: '[Exception] Exception: Exception of type 'System.Exception' was thrown.'. Use UnityEngine.TestTools.LogAssert.Expect
- Test 5 - always success.
Also I can see the correct exception log in Unity3d console for all of these tests. Even for those, that fails.
I can make some conclusions and raise some questions based on these results.
- Firstly, looks like exceptions, that are thrown in async methods are not logged instantly, but written to some kind of buffer, and logged only when this buffer is purged. Also, this buffer purging does not depend on engine
Update
tick, or this dependency is not clear for me. I can say all of this becauseTest5
, where I wait great amount of time success always, butTest3
where I wait only for one engine tick is unstable and looks like this exceptions buffer can either be purged while this tick elapsed or not. - Secondly, for some reason, I have to specify
LogAssert.ignoreFailingMessages = true;
for exceptions logs, that are logged from this buffer, but I don’t have to do it if exception logged explicitly.Test4
andTest5
results illustrate this well.
So the question is how to make a test, that assert exception, raised in async method, logged? And make it most efficient. I mean, the case when I should wait a second is not suitable for auto-tests, of course. I expect, I can do something like this:
[Test]
public void Test()
{
ThrowException();
UnityAPI.ForceLogAllAsyncExceptions(); // I imagine this method
LogAssert.Expect(LogType.Exception, new Regex(".*"));
}
Or any other solutions.