public void SetupPersistentListeners(object runner)
        {
            UnityEventTools.AddPersistentListener((UnityEvent <ITest>)runner.GetType().GetField("testStartedEvent",
                                                                                                BindingFlags.NonPublic | BindingFlags.Instance).GetValue(runner), new UnityAction <ITest>(test =>
            {
                if (!(test is TestMethod))
                {
                    return;
                }
                ourLogger.Verbose("TestStarted : {0}", test.FullName);
                var internalEvent = new TestInternalEvent(TestEventsSender.GetIdFromNUnitTest(test), "", 0, Status.Running, TestEventsSender.GetIdFromNUnitTest(test.Parent));
                TestEventReceived(new TestEvent(EventType.TestStarted, internalEvent));
            })
                                                  );
            UnityEventTools.AddPersistentListener((UnityEvent <ITestResult>)runner.GetType().GetField("testFinishedEvent",
                                                                                                      BindingFlags.NonPublic | BindingFlags.Instance).GetValue(runner), new UnityAction <ITestResult>(result =>
            {
                if (!(result.Test is TestMethod))
                {
                    return;
                }

                var internalEvent = TestEventsSender.GetTestResult(result);
                TestEventReceived(new TestEvent(EventType.TestFinished, internalEvent));
            }));
            UnityEventTools.AddPersistentListener((UnityEvent <ITestResult>)runner.GetType().GetField("runFinishedEvent",
                                                                                                      BindingFlags.NonPublic | BindingFlags.Instance).GetValue(runner),
                                                  new UnityAction <ITestResult>(result =>
            {
                var internalEvent = new TestInternalEvent("", "", 0, Status.Success, "");
                TestEventReceived(new TestEvent(EventType.RunFinished, internalEvent));
            }));
        }
        public void TryLaunchUnitTests()
        {
            try
            {
                var assemblies         = AppDomain.CurrentDomain.GetAssemblies();
                var testEditorAssembly = assemblies
                                         .FirstOrDefault(assembly => assembly.GetName().Name.Equals("UnityEditor.TestRunner"));
                var testEngineAssembly = assemblies
                                         .FirstOrDefault(assembly => assembly.GetName().Name.Equals("UnityEngine.TestRunner"));

                if (testEditorAssembly == null || testEngineAssembly == null)
                {
                    ourLogger.Verbose(
                        "Could not find UnityEditor.TestRunner or UnityEngine.TestRunner assemblies in current AppDomain");
                    return;
                }

                var launcherTypeString = myLaunch.TestMode == TestMode.Edit ?
                                         "UnityEditor.TestTools.TestRunner.EditModeLauncher" :
                                         "UnityEditor.TestTools.TestRunner.PlaymodeLauncher";
                var launcherType = testEditorAssembly.GetType(launcherTypeString);
                if (launcherType == null)
                {
                    string testEditorAssemblyProperties = testEditorAssembly.GetTypes().Select(a => a.Name).Aggregate((a, b) => a + ", " + b);
                    throw new NullReferenceException($"Could not find {launcherTypeString} among {testEditorAssemblyProperties}");
                }

                var filterType = testEngineAssembly.GetType("UnityEngine.TestTools.TestRunner.GUI.TestRunnerFilter");
                if (filterType == null)
                {
                    string testEngineAssemblyProperties = testEngineAssembly.GetTypes().Select(a => a.Name).Aggregate((a, b) => a + ", " + b);
                    throw new NullReferenceException($"Could not find \"UnityEngine.TestTools.TestRunner.GUI.TestRunnerFilter\" among {testEngineAssemblyProperties}");
                }

                var filter    = Activator.CreateInstance(filterType);
                var fieldInfo = filter.GetType().GetField("testNames", BindingFlags.Instance | BindingFlags.Public);
                fieldInfo = fieldInfo ?? filter.GetType().GetField("names", BindingFlags.Instance | BindingFlags.Public);
                if (fieldInfo == null)
                {
                    ourLogger.Verbose("Could not find testNames field via reflection");
                    return;
                }

                var testNameStrings = (object)myLaunch.TestNames.ToArray();
                fieldInfo.SetValue(filter, testNameStrings);

                if (myLaunch.TestMode == TestMode.Play)
                {
                    PlayModeSupport.PlayModeLauncherRun(filter, launcherType, testEditorAssembly, testEngineAssembly);
                }
                else
                {
                    object launcher;
                    if (UnityUtils.UnityVersion >= new Version(2018, 1))
                    {
                        var enumType = testEngineAssembly.GetType("UnityEngine.TestTools.TestPlatform");
                        if (enumType == null)
                        {
                            ourLogger.Verbose("Could not find TestPlatform field via reflection");
                            return;
                        }

                        var assemblyProviderType = testEditorAssembly.GetType("UnityEditor.TestTools.TestRunner.TestInEditorTestAssemblyProvider");
                        var testPlatformVal      = 2; // All = 255, // 0xFF, EditMode = 2, PlayMode = 4,
                        if (assemblyProviderType != null)
                        {
                            var assemblyProvider = Activator.CreateInstance(assemblyProviderType,
                                                                            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null,
                                                                            new[] { Enum.ToObject(enumType, testPlatformVal) }, null);
                            ourLogger.Log(LoggingLevel.INFO, assemblyProvider.ToString());
                            launcher = Activator.CreateInstance(launcherType,
                                                                BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
                                                                null, new[] { filter, assemblyProvider },
                                                                null);
                        }
                        else
                        {
                            launcher = Activator.CreateInstance(launcherType,
                                                                BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
                                                                null, new[] { filter, Enum.ToObject(enumType, testPlatformVal) },
                                                                null);
                        }
                    }
                    else
                    {
                        launcher = Activator.CreateInstance(launcherType,
                                                            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
                                                            null, new[] { filter },
                                                            null);
                    }

                    var runnerField = launcherType.GetField("m_EditModeRunner", BindingFlags.Instance | BindingFlags.NonPublic);
                    if (runnerField == null)
                    {
                        ourLogger.Verbose("Could not find runnerField via reflection");
                        return;
                    }

                    var runner = runnerField.GetValue(launcher);
                    SupportAbort(runner);

                    if (!AdviseTestStarted(runner, "m_TestStartedEvent", test =>
                    {
                        if (!(test is TestMethod))
                        {
                            return;
                        }
                        ourLogger.Verbose("TestStarted : {0}", test.FullName);
                        var tResult = new TestResult(TestEventsSender.GetIdFromNUnitTest(test), string.Empty, 0, Status.Running,
                                                     TestEventsSender.GetIdFromNUnitTest(test.Parent));
                        TestEventsSender.TestStarted(myLaunch, tResult);
                    }))
                    {
                        return;
                    }

                    if (!AdviseTestFinished(runner, "m_TestFinishedEvent", result =>
                    {
                        if (!(result.Test is TestMethod))
                        {
                            return;
                        }
                        var res = TestEventsSender.GetTestResult(result);
                        TestEventsSender.TestFinished(myLaunch, TestEventsSender.GetTestResult(res));
                    }))
                    {
                        return;
                    }

                    if (!AdviseSessionFinished(runner, "m_RunFinishedEvent", result =>
                    {
                        TestEventsSender.RunFinished(myLaunch);
                    }))
                    {
                        return;
                    }

                    var runMethod = launcherType.GetMethod("Run", BindingFlags.Instance | BindingFlags.Public);
                    if (runMethod == null)
                    {
                        ourLogger.Verbose("Could not find runMethod via reflection");
                        return;
                    }

                    //run!
                    runMethod.Invoke(launcher, null);
                }
            }
            catch (Exception e)
            {
                ourLogger.Error(e, "Exception while launching Unity Editor tests.");
            }
        }