private static void TestAfterPlaying() { // Disables the runner located in basic non-testing scene FindObjectsOfType <GameTestRunner>().ForEach(run => run.gameObject.SetActive(false)); var allTestComponents = TestComponent.FindAllTestsOnScene().ToList(); var dynamicTests = allTestComponents.Where(t => t.dynamic).ToList(); var dynamicTestsToRun = dynamicTests.Select(c => c.dynamicTypeName).ToList(); allTestComponents.RemoveAll(dynamicTests.Contains); TestComponent.DisableAllTests(); var testRunner = CleanTestRunner(); testRunner.TestRunnerCallback.Add(new TestCallback()); testRunner.InitRunner(allTestComponents, dynamicTestsToRun); print("*** Start of testing ***"); testRunner.StartCoroutine(testRunner.StateMachine()); if (!testRunner.enabled) { throw new Exception("BuildProject self-assertion failed: Test Runner is not enabled"); } // Makes sure the flag used to keep track of thread exit is initialized correctly TestRunner.ApplicationIsPlaying = true; // Currently not used, moved Passed and Failed functionality to the GameTestRunner if (_testBackgroundThread != null) { Log.i("Interrupting previous test thread"); _testBackgroundThread.Interrupt(); } _testBackgroundThread = new Thread(() => { const int timeoutMinutes = 5; for (var i = 0; i < timeoutMinutes * 30; i++) { if (!TestRunner.ApplicationIsPlaying) { Log.i("Application stopped, exiting test thread"); return; } // _stopTests doesn't currently work, as its callback is never called from the TestRunner if (_stopTests) { GameTestRunner.Passed = true; return; } Thread.Sleep(2000); } Log.e("Test timeout, " + timeoutMinutes + " minute" + (timeoutMinutes == 1 ? "" : "s") + " passed"); GameTestRunner.Failed = true; }); _testBackgroundThread.Start(); }