using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using NUnit.Core; using NUnit.Core.Filters; using UnityEditor; using UnityEngine; using UnityTest.UnitTestRunner; namespace UnityTest { public class NUnitTestEngine : IUnitTestEngine { static readonly string[] k_WhitelistedAssemblies = { "Assembly-CSharp-Editor", "Assembly-Boo-Editor", "Assembly-UnityScript-Editor" }; private TestSuite m_TestSuite; public UnitTestRendererLine GetTests(out UnitTestResult[] results, out string[] categories) { if (m_TestSuite == null) { var assemblies = GetAssembliesWithTests().Select(a => a.Location).ToList(); TestSuite suite = PrepareTestSuite(assemblies); m_TestSuite = suite; } var resultList = new List(); var categoryList = new HashSet(); UnitTestRendererLine lines = null; if (m_TestSuite != null) lines = ParseTestList(m_TestSuite, resultList, categoryList).Single(); results = resultList.ToArray(); categories = categoryList.ToArray(); return lines; } private UnitTestRendererLine[] ParseTestList(Test test, List results, HashSet categories) { foreach (string category in test.Categories) categories.Add(category); if (test is TestMethod) { var result = new UnitTestResult { Test = new UnitTestInfo(test as TestMethod) }; results.Add(result); return new[] { new TestLine(test as TestMethod, result.Id) }; } GroupLine group = null; if (test is TestSuite) group = new GroupLine(test as TestSuite); var namespaceList = new List(new[] {group}); foreach (Test result in test.Tests) { if (result is NamespaceSuite || test is TestAssembly) namespaceList.AddRange(ParseTestList(result, results, categories)); else group.AddChildren(ParseTestList(result, results, categories)); } namespaceList.Sort(); return namespaceList.ToArray(); } public void RunTests(ITestRunnerCallback testRunnerEventListener) { RunTests(TestFilter.Empty, testRunnerEventListener); } public void RunTests(TestFilter filter, ITestRunnerCallback testRunnerEventListener) { try { if (testRunnerEventListener != null) testRunnerEventListener.RunStarted(m_TestSuite.TestName.FullName, m_TestSuite.TestCount); ExecuteTestSuite(m_TestSuite, testRunnerEventListener, filter); if (testRunnerEventListener != null) testRunnerEventListener.RunFinished(); } catch (Exception e) { Debug.LogException(e); if (testRunnerEventListener != null) testRunnerEventListener.RunFinishedException(e); } } public static Assembly[] GetAssembliesWithTests() { var libs = new List(); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (assembly.GetReferencedAssemblies().All(a => a.Name != "nunit.framework")) continue; if (assembly.Location.Replace('\\', '/').StartsWith(Application.dataPath) || k_WhitelistedAssemblies.Contains(assembly.GetName().Name)) libs.Add(assembly); } return libs.ToArray(); } private TestSuite PrepareTestSuite(List assemblyList) { CoreExtensions.Host.InitializeService(); var testPackage = new TestPackage(PlayerSettings.productName, assemblyList); var builder = new TestSuiteBuilder(); TestExecutionContext.CurrentContext.TestPackage = testPackage; TestSuite suite = builder.Build(testPackage); return suite; } private void ExecuteTestSuite(TestSuite suite, ITestRunnerCallback testRunnerEventListener, TestFilter filter) { EventListener eventListener; if (testRunnerEventListener == null) eventListener = new NullListener(); else eventListener = new TestRunnerEventListener(testRunnerEventListener); TestExecutionContext.CurrentContext.Out = new EventListenerTextWriter(eventListener, TestOutputType.Out); TestExecutionContext.CurrentContext.Error = new EventListenerTextWriter(eventListener, TestOutputType.Error); suite.Run(eventListener, GetFilter(filter)); } private ITestFilter GetFilter(TestFilter filter) { var nUnitFilter = new AndFilter(); if (filter.names != null && filter.names.Length > 0) nUnitFilter.Add(new SimpleNameFilter(filter.names)); if (filter.categories != null && filter.categories.Length > 0) nUnitFilter.Add(new CategoryFilter(filter.categories)); if (filter.objects != null && filter.objects.Length > 0) nUnitFilter.Add(new OrFilter(filter.objects.Where(o => o is TestName).Select(o => new NameFilter(o as TestName)).ToArray())); return nUnitFilter; } public class TestRunnerEventListener : EventListener { private readonly ITestRunnerCallback m_TestRunnerEventListener; private StringBuilder m_testLog; public TestRunnerEventListener(ITestRunnerCallback testRunnerEventListener) { m_TestRunnerEventListener = testRunnerEventListener; } public void RunStarted(string name, int testCount) { m_TestRunnerEventListener.RunStarted(name, testCount); } public void RunFinished(NUnit.Core.TestResult result) { m_TestRunnerEventListener.RunFinished(); } public void RunFinished(Exception exception) { m_TestRunnerEventListener.RunFinishedException(exception); } public void TestStarted(TestName testName) { m_testLog = new StringBuilder(); m_TestRunnerEventListener.TestStarted(testName.FullName); } public void TestFinished(NUnit.Core.TestResult result) { m_TestRunnerEventListener.TestFinished(result.UnitTestResult(m_testLog.ToString())); m_testLog = null; } public void SuiteStarted(TestName testName) { } public void SuiteFinished(NUnit.Core.TestResult result) { } public void UnhandledException(Exception exception) { } public void TestOutput(TestOutput testOutput) { if (m_testLog != null) m_testLog.AppendLine(testOutput.Text); } } } }