static int RunProject(XunitProject project, bool serialize, bool?parallelizeAssemblies, bool?parallelizeTestCollections, int?maxThreadCount, bool diagnosticMessages, bool noColor, bool noAppDomain, bool failSkips) { XElement assembliesElement = null; var clockTime = Stopwatch.StartNew(); var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; var consoleLock = new object(); if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); } if (needsXml) { assembliesElement = new XElement("assemblies"); } var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(consoleLock, assembly, serialize, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, noAppDomain, failSkips, project.Filters))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) { assembliesElement.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(consoleLock, assembly, serialize, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, noAppDomain, failSkips, project.Filters); if (assemblyElement != null) { assembliesElement.Add(assemblyElement); } } } clockTime.Stop(); if (completionMessages.Count > 0) { reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } } Directory.SetCurrentDirectory(originalWorkingFolder); xmlTransformers.ForEach(transformer => transformer(assembliesElement)); return(failed ? 1 : completionMessages.Values.Sum(summary => summary.Failed)); }
static int RunProject(string defaultDirectory, XunitProject project, bool teamcity, bool appVeyor, bool?parallelizeAssemblies, bool?parallelizeTestCollections, int?maxThreadCount) { XElement assembliesElement = null; var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; var consoleLock = new object(); if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssembly); } if (needsXml) { assembliesElement = new XElement("assemblies"); } var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { var clockTime = Stopwatch.StartNew(); if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(consoleLock, defaultDirectory, assembly, needsXml, teamcity, appVeyor, parallelizeTestCollections, maxThreadCount, project.Filters))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) { assembliesElement.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(consoleLock, defaultDirectory, assembly, needsXml, teamcity, appVeyor, parallelizeTestCollections, maxThreadCount, project.Filters); if (assemblyElement != null) { assembliesElement.Add(assemblyElement); } } } clockTime.Stop(); if (completionMessages.Count > 0) { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(); Console.WriteLine("=== TEST EXECUTION SUMMARY ==="); Console.ForegroundColor = ConsoleColor.Gray; var totalTestsRun = completionMessages.Values.Sum(summary => summary.Total); var totalTestsFailed = completionMessages.Values.Sum(summary => summary.Failed); var totalTestsSkipped = completionMessages.Values.Sum(summary => summary.Skipped); var totalTime = completionMessages.Values.Sum(summary => summary.Time).ToString("0.000s"); var totalErrors = completionMessages.Values.Sum(summary => summary.Errors); var longestAssemblyName = completionMessages.Keys.Max(key => key.Length); var longestTotal = totalTestsRun.ToString().Length; var longestFailed = totalTestsFailed.ToString().Length; var longestSkipped = totalTestsSkipped.ToString().Length; var longestTime = totalTime.Length; var longestErrors = totalErrors.ToString().Length; foreach (var message in completionMessages.OrderBy(m => m.Key)) { Console.WriteLine(" {0} Total: {1}, Errors: {2}, Failed: {3}, Skipped: {4}, Time: {5}", message.Key.PadRight(longestAssemblyName), message.Value.Total.ToString().PadLeft(longestTotal), message.Value.Errors.ToString().PadLeft(longestErrors), message.Value.Failed.ToString().PadLeft(longestFailed), message.Value.Skipped.ToString().PadLeft(longestSkipped), message.Value.Time.ToString("0.000s").PadLeft(longestTime)); } if (completionMessages.Count > 1) { Console.WriteLine(" {0} {1} {2} {3} {4} {5}" + Environment.NewLine + " {6} {7} {8} {9} {10} {11} ({12})", " ".PadRight(longestAssemblyName), "-".PadRight(longestTotal, '-'), "-".PadRight(longestErrors, '-'), "-".PadRight(longestFailed, '-'), "-".PadRight(longestSkipped, '-'), "-".PadRight(longestTime, '-'), "GRAND TOTAL:".PadLeft(longestAssemblyName), totalTestsRun, totalErrors, totalTestsFailed, totalTestsSkipped, totalTime, clockTime.Elapsed.TotalSeconds.ToString("0.000s")); } } } Directory.SetCurrentDirectory(originalWorkingFolder); xmlTransformers.ForEach(transformer => transformer(assembliesElement)); return(failed ? 1 : completionMessages.Values.Sum(summary => summary.Failed)); }
public override bool Execute() { RemotingUtility.CleanUpRegisteredChannels(); if (TeamCity) { Log.LogError("The 'TeamCity' property is deprecated. Please set the 'Reporter' property to 'teamcity' instead."); return false; } if (Verbose) { Log.LogError("The 'Verbose' property is deprecated. Please set the 'Reporter' property to 'verbose' instead."); return false; } XElement assembliesElement = null; var environment = string.Format("{0}-bit .NET {1}", IntPtr.Size * 8, Environment.Version); if (NeedsXml) assembliesElement = new XElement("assemblies"); switch (MaxParallelThreads) { case null: case "default": break; case "unlimited": maxThreadCount = 0; break; default: int threadValue; if (!int.TryParse(MaxParallelThreads, out threadValue) || threadValue < 0) { Log.LogError("MaxParallelThreads value '{0}' is invalid: must be 'default', 'unlimited', or a positive number", MaxParallelThreads); return false; } maxThreadCount = threadValue; break; } var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { var reporters = GetAvailableRunnerReporters(); var reporter = reporters.FirstOrDefault(r => r.IsEnvironmentallyEnabled); if (reporter == null && !string.IsNullOrWhiteSpace(Reporter)) { reporter = reporters.FirstOrDefault(r => string.Equals(r.RunnerSwitch, Reporter, StringComparison.OrdinalIgnoreCase)); if (reporter == null) { var switchableReporters = reporters.Where(r => !string.IsNullOrWhiteSpace(r.RunnerSwitch)).Select(r => r.RunnerSwitch.ToLowerInvariant()).OrderBy(x => x).ToList(); if (switchableReporters.Count == 0) Log.LogError("Reporter value '{0}' is invalid. There are no available reporters.", Reporter); else Log.LogError("Reporter value '{0}' is invalid. Available reporters: {1}", Reporter, string.Join(", ", switchableReporters)); return false; } } if (reporter == null) reporter = new DefaultRunnerReporter(); logger = new MSBuildLogger(Log); reporterMessageHandler = reporter.CreateMessageHandler(logger); if (!NoLogo) Log.LogMessage(MessageImportance.High, "xUnit.net MSBuild Runner ({0})", environment); var project = new XunitProject(); foreach (var assembly in Assemblies) { var assemblyFileName = assembly.GetMetadata("FullPath"); var configFileName = assembly.GetMetadata("ConfigFile"); if (configFileName != null && configFileName.Length == 0) configFileName = null; project.Add(new XunitProjectAssembly { AssemblyFilename = assemblyFileName, ConfigFilename = configFileName, ShadowCopy = ShadowCopy }); } if (WorkingFolder != null) Directory.SetCurrentDirectory(WorkingFolder); var clockTime = Stopwatch.StartNew(); if (!parallelizeAssemblies.HasValue) parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(assembly))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) assembliesElement.Add(assemblyElement); } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(assembly); if (assemblyElement != null) assembliesElement.Add(assemblyElement); } } clockTime.Stop(); if (completionMessages.Count > 0) reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } Directory.SetCurrentDirectory(WorkingFolder ?? originalWorkingFolder); if (NeedsXml) { if (Xml != null) assembliesElement.Save(Xml.GetMetadata("FullPath")); if (XmlV1 != null) Transform("xUnit1.xslt", assembliesElement, XmlV1); if (Html != null) Transform("HTML.xslt", assembliesElement, Html); if (NUnit != null) Transform("NUnitXml.xslt", assembliesElement, NUnit); } return ExitCode == 0; }
int RunProject(XunitProject project, bool?parallelizeAssemblies, bool?parallelizeTestCollections, int?maxThreadCount, bool diagnosticMessages, bool noColor, AppDomainSupport?appDomains, bool failSkips, bool designTime, bool list, IReadOnlyList <string> designTimeFullyQualifiedNames) { XElement assembliesElement = null; var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; var consoleLock = new object(); if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => { var assm = (XunitProjectAssembly2)assembly; return(assm.ConfigFilename != null ? assm.Configuration.ParallelizeAssemblyOrDefault : assm.ConfigurationStream.ParallelizeAssemblyOrDefault); }); } if (needsXml) { assembliesElement = new XElement("assemblies"); } var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { var clockTime = Stopwatch.StartNew(); if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => TaskRun(() => ExecuteAssembly( consoleLock, (XunitProjectAssembly2)assembly, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, appDomains, failSkips, project.Filters, designTime, list, designTimeFullyQualifiedNames))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) { assembliesElement.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly( consoleLock, (XunitProjectAssembly2)assembly, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, appDomains, failSkips, project.Filters, designTime, list, designTimeFullyQualifiedNames); if (assemblyElement != null) { assembliesElement.Add(assemblyElement); } } } SendTestCompletedIfNecessary(designTime, list); clockTime.Stop(); if (completionMessages.Count > 0) { reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } } Directory.SetCurrentDirectory(originalWorkingFolder); foreach (var transformer in xmlTransformers) { transformer(assembliesElement); } return(failed ? 1 : completionMessages.Values.Sum(summary => summary.Failed)); }
static int RunProject(XunitProject project, bool serialize, bool? parallelizeAssemblies, bool? parallelizeTestCollections, int? maxThreadCount, bool diagnosticMessages, bool noColor, bool noAppDomain, bool failSkips) { XElement assembliesElement = null; var clockTime = Stopwatch.StartNew(); var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; var consoleLock = new object(); if (!parallelizeAssemblies.HasValue) parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); if (needsXml) assembliesElement = new XElement("assemblies"); var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(consoleLock, assembly, serialize, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, noAppDomain, failSkips, project.Filters))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) assembliesElement.Add(assemblyElement); } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(consoleLock, assembly, serialize, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, noAppDomain, failSkips, project.Filters); if (assemblyElement != null) assembliesElement.Add(assemblyElement); } } clockTime.Stop(); if (completionMessages.Count > 0) reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } Directory.SetCurrentDirectory(originalWorkingFolder); xmlTransformers.ForEach(transformer => transformer(assembliesElement)); return failed ? 1 : completionMessages.Values.Sum(summary => summary.Failed); }
int RunProject(XunitProject project, bool serialize, bool?parallelizeAssemblies, bool?parallelizeTestCollections, int?maxThreadCount, bool diagnosticMessages, bool noColor, AppDomainSupport?appDomains, bool failSkips, bool stopOnFail, bool internalDiagnosticMessages) { XElement assembliesElement = null; var clockTime = Stopwatch.StartNew(); var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); } logger.LogMessage($"NeedsXml: {needsXml}"); if (needsXml) { assembliesElement = new XElement("assemblies"); } var originalWorkingFolder = Directory.GetCurrentDirectory(); if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(consoleLock, assembly, serialize, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, appDomains, failSkips, stopOnFail, project.Filters, internalDiagnosticMessages))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) { logger.LogMessage($"AssembliesElement: {assembliesElement?.ToString()}"); assembliesElement.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(consoleLock, assembly, serialize, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, appDomains, failSkips, stopOnFail, project.Filters, internalDiagnosticMessages); if (assemblyElement != null) { logger.LogMessage($"AssembliesElement before add assembly {assembly.AssemblyFilename}: {assembliesElement?.ToString()}"); assembliesElement.Add(assemblyElement); } } } clockTime.Stop(); logger.LogMessage($"AssembliesElement before adding timestamp: {assembliesElement?.ToString()}"); if (assembliesElement != null) { assembliesElement.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); } if (completionMessages.Count > 0) { reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } Directory.SetCurrentDirectory(originalWorkingFolder); xmlTransformers.ForEach(transformer => transformer(assembliesElement)); return(failed ? 1 : completionMessages.Values.Sum(summary => summary.Failed)); }
async ValueTask <int> RunProject( XunitProject project, _IMessageSink reporterMessageHandler) { XElement?assembliesElement = null; var clockTime = Stopwatch.StartNew(); var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; // TODO: Parallelize the ones that will parallelize, and then run the rest sequentially? var parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); if (needsXml) { assembliesElement = new XElement("assemblies"); } var originalWorkingFolder = Directory.GetCurrentDirectory(); if (parallelizeAssemblies) { var tasks = project.Assemblies.Select( assembly => Task.Run( () => ExecuteAssembly( assembly, needsXml, reporterMessageHandler ).AsTask() ) ); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.WhereNotNull()) { assembliesElement?.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = await ExecuteAssembly( assembly, needsXml, reporterMessageHandler ); if (assemblyElement != null) { assembliesElement?.Add(assemblyElement); } } } clockTime.Stop(); if (assembliesElement != null) { assembliesElement.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); } if (completionMessages.Count > 0) { var summaries = new TestExecutionSummaries { ElapsedClockTime = clockTime.Elapsed }; foreach (var completionMessage in completionMessages.OrderBy(kvp => kvp.Key)) { summaries.Add(completionMessage.Key, completionMessage.Value); } reporterMessageHandler.OnMessage(summaries); } Directory.SetCurrentDirectory(originalWorkingFolder); if (assembliesElement != null) { xmlTransformers.ForEach(transformer => transformer(assembliesElement)); } return(failed ? 1 : completionMessages.Values.Sum(summary => summary.Failed + summary.Errors)); }
public override bool Execute() { RemotingUtility.CleanUpRegisteredChannels(); XElement assembliesElement = null; var environment = $"{IntPtr.Size * 8}-bit .NET {Environment.Version}"; if (NeedsXml) { assembliesElement = new XElement("assemblies"); } switch (MaxParallelThreads) { case null: case "default": break; case "unlimited": maxThreadCount = -1; break; default: int threadValue; if (!int.TryParse(MaxParallelThreads, out threadValue) || threadValue < 1) { Log.LogError("MaxParallelThreads value '{0}' is invalid: must be 'default', 'unlimited', or a positive number", MaxParallelThreads); return(false); } maxThreadCount = threadValue; break; } var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { var reporter = GetReporter(); if (reporter == null) { return(false); } logger = new MSBuildLogger(Log); reporterMessageHandler = MessageSinkWithTypesAdapter.Wrap(reporter.CreateMessageHandler(logger)); if (!NoLogo) { Log.LogMessage(MessageImportance.High, "xUnit.net MSBuild Runner ({0})", environment); } var project = new XunitProject(); foreach (var assembly in Assemblies) { var assemblyFileName = assembly.GetMetadata("FullPath"); var configFileName = assembly.GetMetadata("ConfigFile"); if (configFileName != null && configFileName.Length == 0) { configFileName = null; } var projectAssembly = new XunitProjectAssembly { AssemblyFilename = assemblyFileName, ConfigFilename = configFileName }; if (shadowCopy.HasValue) { projectAssembly.Configuration.ShadowCopy = shadowCopy; } project.Add(projectAssembly); } if (WorkingFolder != null) { Directory.SetCurrentDirectory(WorkingFolder); } var clockTime = Stopwatch.StartNew(); if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); } if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(assembly))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) { assembliesElement.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(assembly); if (assemblyElement != null) { assembliesElement.Add(assemblyElement); } } } clockTime.Stop(); if (assembliesElement != null) { assembliesElement.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); } if (completionMessages.Count > 0) { reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } } Directory.SetCurrentDirectory(WorkingFolder ?? originalWorkingFolder); if (NeedsXml) { if (Xml != null) { assembliesElement.Save(Xml.GetMetadata("FullPath")); } if (XmlV1 != null) { Transform("xUnit1.xslt", assembliesElement, XmlV1); } if (Html != null) { Transform("HTML.xslt", assembliesElement, Html); } if (NUnit != null) { Transform("NUnitXml.xslt", assembliesElement, NUnit); } } // ExitCode is set to 1 for test failures and -1 for Exceptions. return(ExitCode == 0 || (ExitCode == 1 && IgnoreFailures)); }
static int RunProject(string defaultDirectory, XunitProject project, bool teamcity, bool appVeyor, bool showProgress, bool? parallelizeAssemblies, bool? parallelizeTestCollections, int? maxThreadCount) { XElement assembliesElement = null; var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; var consoleLock = new object(); if (!parallelizeAssemblies.HasValue) parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssembly ?? false); if (needsXml) assembliesElement = new XElement("assemblies"); var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { var clockTime = Stopwatch.StartNew(); if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(consoleLock, defaultDirectory, assembly, needsXml, teamcity, appVeyor, showProgress, parallelizeTestCollections, maxThreadCount, project.Filters))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) assembliesElement.Add(assemblyElement); } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(consoleLock, defaultDirectory, assembly, needsXml, teamcity, appVeyor, showProgress, parallelizeTestCollections, maxThreadCount, project.Filters); if (assemblyElement != null) assembliesElement.Add(assemblyElement); } } clockTime.Stop(); if (completionMessages.Count > 0) { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(); Console.WriteLine("=== TEST EXECUTION SUMMARY ==="); Console.ForegroundColor = ConsoleColor.Gray; var totalTestsRun = completionMessages.Values.Sum(summary => summary.Total); var totalTestsFailed = completionMessages.Values.Sum(summary => summary.Failed); var totalTestsSkipped = completionMessages.Values.Sum(summary => summary.Skipped); var totalTime = completionMessages.Values.Sum(summary => summary.Time).ToString("0.000s"); var totalErrors = completionMessages.Values.Sum(summary => summary.Errors); var longestAssemblyName = completionMessages.Keys.Max(key => key.Length); var longestTotal = totalTestsRun.ToString().Length; var longestFailed = totalTestsFailed.ToString().Length; var longestSkipped = totalTestsSkipped.ToString().Length; var longestTime = totalTime.Length; var longestErrors = totalErrors.ToString().Length; foreach (var message in completionMessages.OrderBy(m => m.Key)) Console.WriteLine(" {0} Total: {1}, Errors: {2}, Failed: {3}, Skipped: {4}, Time: {5}", message.Key.PadRight(longestAssemblyName), message.Value.Total.ToString().PadLeft(longestTotal), message.Value.Errors.ToString().PadLeft(longestErrors), message.Value.Failed.ToString().PadLeft(longestFailed), message.Value.Skipped.ToString().PadLeft(longestSkipped), message.Value.Time.ToString("0.000s").PadLeft(longestTime)); if (completionMessages.Count > 1) Console.WriteLine(" {0} {1} {2} {3} {4} {5}" + Environment.NewLine + " {6} {7} {8} {9} {10} {11} ({12})", " ".PadRight(longestAssemblyName), "-".PadRight(longestTotal, '-'), "-".PadRight(longestErrors, '-'), "-".PadRight(longestFailed, '-'), "-".PadRight(longestSkipped, '-'), "-".PadRight(longestTime, '-'), "GRAND TOTAL:".PadLeft(longestAssemblyName), totalTestsRun, totalErrors, totalTestsFailed, totalTestsSkipped, totalTime, clockTime.Elapsed.TotalSeconds.ToString("0.000s")); } } Directory.SetCurrentDirectory(originalWorkingFolder); xmlTransformers.ForEach(transformer => transformer(assembliesElement)); return failed ? 1 : completionMessages.Values.Sum(summary => summary.Failed); }
public override bool Execute() { Guard.ArgumentNotNull(nameof(Assemblies), Assemblies); RemotingUtility.CleanUpRegisteredChannels(); XElement?assembliesElement = null; if (NeedsXml) { assembliesElement = new XElement("assemblies"); } var appDomains = default(AppDomainSupport?); switch (AppDomains?.ToLowerInvariant()) { case null: break; case "ifavailable": appDomains = AppDomainSupport.IfAvailable; break; case "true": case "required": appDomains = AppDomainSupport.Required; break; case "false": case "denied": appDomains = AppDomainSupport.Denied; break; default: Log.LogError("AppDomains value '{0}' is invalid: must be 'ifavailable', 'required', or 'denied'", AppDomains); return(false); } switch (MaxParallelThreads) { case null: case "default": break; case "unlimited": maxThreadCount = -1; break; default: int threadValue; if (!int.TryParse(MaxParallelThreads, out threadValue) || threadValue < 1) { Log.LogError("MaxParallelThreads value '{0}' is invalid: must be 'default', 'unlimited', or a positive number", MaxParallelThreads); return(false); } maxThreadCount = threadValue; break; } var originalWorkingFolder = Directory.GetCurrentDirectory(); var internalDiagnosticsMessageSink = DiagnosticMessageSink.ForInternalDiagnostics(Log, InternalDiagnosticMessages); using (AssemblyHelper.SubscribeResolveForAssembly(typeof(xunit), internalDiagnosticsMessageSink)) { var reporter = GetReporter(); if (reporter == null) { return(false); } try { logger = new MSBuildLogger(Log); reporterMessageHandler = reporter.CreateMessageHandler(logger, internalDiagnosticsMessageSink).GetAwaiter().GetResult(); if (!NoLogo) { Log.LogMessage(MessageImportance.High, $"xUnit.net v3 MSBuild Runner v{ThisAssembly.AssemblyInformationalVersion} ({IntPtr.Size * 8}-bit {RuntimeInformation.FrameworkDescription})"); } var project = new XunitProject(); foreach (var assembly in Assemblies) { var assemblyFileName = assembly.GetMetadata("FullPath"); var configFileName = assembly.GetMetadata("ConfigFile"); if (configFileName != null && configFileName.Length == 0) { configFileName = null; } var targetFramework = AssemblyUtility.GetTargetFramework(assemblyFileName); var projectAssembly = new XunitProjectAssembly(project) { AssemblyFilename = assemblyFileName, ConfigFilename = configFileName, TargetFramework = targetFramework }; ConfigReader.Load(projectAssembly.Configuration, assemblyFileName, configFileName); if (shadowCopy.HasValue) { projectAssembly.Configuration.ShadowCopy = shadowCopy; } project.Add(projectAssembly); } if (WorkingFolder != null) { Directory.SetCurrentDirectory(WorkingFolder); } var clockTime = Stopwatch.StartNew(); if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); } if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(assembly, appDomains).AsTask())); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.WhereNotNull()) { assembliesElement !.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(assembly, appDomains); if (assemblyElement != null) { assembliesElement !.Add(assemblyElement); } } } clockTime.Stop(); if (assembliesElement != null) { assembliesElement.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); } if (completionMessages.Count > 0) { var summaries = new TestExecutionSummaries { ElapsedClockTime = clockTime.Elapsed }; foreach (var completionMessage in completionMessages.OrderBy(kvp => kvp.Key)) { summaries.Add(completionMessage.Key, completionMessage.Value); } reporterMessageHandler.OnMessage(summaries); } } finally { reporter.DisposeAsync().GetAwaiter().GetResult(); } } Directory.SetCurrentDirectory(WorkingFolder ?? originalWorkingFolder); if (NeedsXml && assembliesElement != null) { if (Xml != null) { TransformFactory.Transform("xml", assembliesElement, Xml.GetMetadata("FullPath")); } if (XmlV1 != null) { TransformFactory.Transform("xmlv1", assembliesElement, XmlV1.GetMetadata("FullPath")); } if (Html != null) { TransformFactory.Transform("html", assembliesElement, Html.GetMetadata("FullPath")); } if (NUnit != null) { TransformFactory.Transform("nunit", assembliesElement, NUnit.GetMetadata("FullPath")); } if (JUnit != null) { TransformFactory.Transform("junit", assembliesElement, JUnit.GetMetadata("FullPath")); } } // ExitCode is set to 1 for test failures and -1 for Exceptions. return(ExitCode == 0 || (ExitCode == 1 && IgnoreFailures)); }
public override bool Execute() { RemotingUtility.CleanUpRegisteredChannels(); XElement assembliesElement = null; var environment = $"{IntPtr.Size * 8}-bit .NET {Environment.Version}"; if (NeedsXml) assembliesElement = new XElement("assemblies"); switch (MaxParallelThreads) { case null: case "default": break; case "unlimited": maxThreadCount = -1; break; default: int threadValue; if (!int.TryParse(MaxParallelThreads, out threadValue) || threadValue < 1) { Log.LogError("MaxParallelThreads value '{0}' is invalid: must be 'default', 'unlimited', or a positive number", MaxParallelThreads); return false; } maxThreadCount = threadValue; break; } var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { var reporter = GetReporter(); if (reporter == null) return false; logger = new MSBuildLogger(Log); reporterMessageHandler = MessageSinkWithTypesAdapter.Wrap(reporter.CreateMessageHandler(logger)); if (!NoLogo) Log.LogMessage(MessageImportance.High, "xUnit.net MSBuild Runner ({0})", environment); var project = new XunitProject(); foreach (var assembly in Assemblies) { var assemblyFileName = assembly.GetMetadata("FullPath"); var configFileName = assembly.GetMetadata("ConfigFile"); if (configFileName != null && configFileName.Length == 0) configFileName = null; var projectAssembly = new XunitProjectAssembly { AssemblyFilename = assemblyFileName, ConfigFilename = configFileName }; if (shadowCopy.HasValue) projectAssembly.Configuration.ShadowCopy = shadowCopy; project.Add(projectAssembly); } if (WorkingFolder != null) Directory.SetCurrentDirectory(WorkingFolder); var clockTime = Stopwatch.StartNew(); if (!parallelizeAssemblies.HasValue) parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(assembly))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) assembliesElement.Add(assemblyElement); } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(assembly); if (assemblyElement != null) assembliesElement.Add(assemblyElement); } } clockTime.Stop(); if (assembliesElement != null) assembliesElement.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); if (completionMessages.Count > 0) reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } Directory.SetCurrentDirectory(WorkingFolder ?? originalWorkingFolder); if (NeedsXml) { if (Xml != null) assembliesElement.Save(Xml.GetMetadata("FullPath")); if (XmlV1 != null) Transform("xUnit1.xslt", assembliesElement, XmlV1); if (Html != null) Transform("HTML.xslt", assembliesElement, Html); if (NUnit != null) Transform("NUnitXml.xslt", assembliesElement, NUnit); } // ExitCode is set to 1 for test failures and -1 for Exceptions. return ExitCode == 0 || (ExitCode == 1 && IgnoreFailures); }
public override bool Execute() { RemotingUtility.CleanUpRegisteredChannels(); if (TeamCity) { Log.LogError("The 'TeamCity' property is deprecated. Please set the 'Reporter' property to 'teamcity' instead."); return(false); } if (Verbose) { Log.LogError("The 'Verbose' property is deprecated. Please set the 'Reporter' property to 'verbose' instead."); return(false); } XElement assembliesElement = null; var environment = $"{IntPtr.Size * 8}-bit .NET {Environment.Version}"; if (NeedsXml) { assembliesElement = new XElement("assemblies"); } switch (MaxParallelThreads) { case null: case "default": break; case "unlimited": maxThreadCount = -1; break; default: int threadValue; if (!int.TryParse(MaxParallelThreads, out threadValue) || threadValue < 1) { Log.LogError("MaxParallelThreads value '{0}' is invalid: must be 'default', 'unlimited', or a positive number", MaxParallelThreads); return(false); } maxThreadCount = threadValue; break; } var originalWorkingFolder = Directory.GetCurrentDirectory(); using (AssemblyHelper.SubscribeResolve()) { var reporters = GetAvailableRunnerReporters(); var reporter = reporters.FirstOrDefault(r => r.IsEnvironmentallyEnabled); if (reporter == null && !string.IsNullOrWhiteSpace(Reporter)) { reporter = reporters.FirstOrDefault(r => string.Equals(r.RunnerSwitch, Reporter, StringComparison.OrdinalIgnoreCase)); if (reporter == null) { var switchableReporters = reporters.Where(r => !string.IsNullOrWhiteSpace(r.RunnerSwitch)).Select(r => r.RunnerSwitch.ToLowerInvariant()).OrderBy(x => x).ToList(); if (switchableReporters.Count == 0) { Log.LogError("Reporter value '{0}' is invalid. There are no available reporters.", Reporter); } else { Log.LogError("Reporter value '{0}' is invalid. Available reporters: {1}", Reporter, string.Join(", ", switchableReporters)); } return(false); } } if (reporter == null) { reporter = new DefaultRunnerReporter(); } logger = new MSBuildLogger(Log); reporterMessageHandler = reporter.CreateMessageHandler(logger); if (!NoLogo) { Log.LogMessage(MessageImportance.High, "xUnit.net MSBuild Runner ({0})", environment); } var project = new XunitProject(); foreach (var assembly in Assemblies) { var assemblyFileName = assembly.GetMetadata("FullPath"); var configFileName = assembly.GetMetadata("ConfigFile"); if (configFileName != null && configFileName.Length == 0) { configFileName = null; } var projectAssembly = new XunitProjectAssembly { AssemblyFilename = assemblyFileName, ConfigFilename = configFileName }; if (shadowCopy.HasValue) { projectAssembly.Configuration.ShadowCopy = shadowCopy; } project.Add(projectAssembly); } if (WorkingFolder != null) { Directory.SetCurrentDirectory(WorkingFolder); } var clockTime = Stopwatch.StartNew(); if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); } if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(assembly))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) { assembliesElement.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(assembly); if (assemblyElement != null) { assembliesElement.Add(assemblyElement); } } } clockTime.Stop(); if (completionMessages.Count > 0) { reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } } Directory.SetCurrentDirectory(WorkingFolder ?? originalWorkingFolder); if (NeedsXml) { if (Xml != null) { assembliesElement.Save(Xml.GetMetadata("FullPath")); } if (XmlV1 != null) { Transform("xUnit1.xslt", assembliesElement, XmlV1); } if (Html != null) { Transform("HTML.xslt", assembliesElement, Html); } if (NUnit != null) { Transform("NUnitXml.xslt", assembliesElement, NUnit); } } return(ExitCode == 0); }
public override bool Execute() { RemotingUtility.CleanUpRegisteredChannels(); XElement assembliesElement = null; var environment = $"{IntPtr.Size * 8}-bit {CrossPlatform.Version}"; if (NeedsXml) { assembliesElement = new XElement("assemblies"); } var appDomains = default(AppDomainSupport?); switch (AppDomains?.ToLowerInvariant()) // Using ToLowerInvariant() here for back compat for when this was a boolean { case null: break; case "ifavailable": appDomains = AppDomainSupport.IfAvailable; break; case "true": case "required": appDomains = AppDomainSupport.Required; break; case "false": case "denied": appDomains = AppDomainSupport.Denied; break; default: Log.LogError("AppDomains value '{0}' is invalid: must be 'ifavailable', 'required', or 'denied'", AppDomains); return(false); } switch (MaxParallelThreads) { case null: case "default": break; case "unlimited": maxThreadCount = -1; break; default: int threadValue; if (!int.TryParse(MaxParallelThreads, out threadValue) || threadValue < 1) { Log.LogError("MaxParallelThreads value '{0}' is invalid: must be 'default', 'unlimited', or a positive number", MaxParallelThreads); return(false); } maxThreadCount = threadValue; break; } var originalWorkingFolder = Directory.GetCurrentDirectory(); var internalDiagnosticsMessageSink = DiagnosticMessageSink.ForInternalDiagnostics(Log, InternalDiagnosticMessages); using (AssemblyHelper.SubscribeResolveForAssembly(typeof(xunit), internalDiagnosticsMessageSink)) { var reporter = GetReporter(); if (reporter == null) { return(false); } logger = new MSBuildLogger(Log); reporterMessageHandler = MessageSinkWithTypesAdapter.Wrap(reporter.CreateMessageHandler(logger)); if (!NoLogo) { var versionAttribute = typeof(xunit).GetTypeInfo().Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>(); Log.LogMessage(MessageImportance.High, $"xUnit.net MSBuild Runner v{versionAttribute.InformationalVersion} ({environment})"); } var project = new XunitProject(); foreach (var assembly in Assemblies) { var assemblyFileName = assembly.GetMetadata("FullPath"); var configFileName = assembly.GetMetadata("ConfigFile"); if (configFileName != null && configFileName.Length == 0) { configFileName = null; } var projectAssembly = new XunitProjectAssembly { AssemblyFilename = assemblyFileName, ConfigFilename = configFileName }; if (shadowCopy.HasValue) { projectAssembly.Configuration.ShadowCopy = shadowCopy; } project.Add(projectAssembly); } if (WorkingFolder != null) { Directory.SetCurrentDirectory(WorkingFolder); } var clockTime = Stopwatch.StartNew(); if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); } if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select(assembly => Task.Run(() => ExecuteAssembly(assembly, appDomains))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); foreach (var assemblyElement in results.Where(result => result != null)) { assembliesElement.Add(assemblyElement); } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly(assembly, appDomains); if (assemblyElement != null) { assembliesElement.Add(assemblyElement); } } } clockTime.Stop(); if (assembliesElement != null) { assembliesElement.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); } if (completionMessages.Count > 0) { reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, completionMessages.OrderBy(kvp => kvp.Key).ToList())); } } Directory.SetCurrentDirectory(WorkingFolder ?? originalWorkingFolder); if (NeedsXml) { if (Xml != null) { using (var xmlStream = new FileStream(Xml.GetMetadata("FullPath"), FileMode.OpenOrCreate, FileAccess.Write)) assembliesElement.Save(xmlStream); } if (XmlV1 != null) { CrossPlatform.Transform(logger, "XmlV1", "xUnit1.xslt", assembliesElement, XmlV1); } if (Html != null) { CrossPlatform.Transform(logger, "Html", "HTML.xslt", assembliesElement, Html); } if (NUnit != null) { CrossPlatform.Transform(logger, "NUnit", "NUnitXml.xslt", assembliesElement, NUnit); } if (JUnit != null) { CrossPlatform.Transform(logger, "JUnit", "JUnitXml.xslt", assembliesElement, JUnit); } } // ExitCode is set to 1 for test failures and -1 for Exceptions. return(ExitCode == 0 || (ExitCode == 1 && IgnoreFailures)); }
/* * private void PrintUsage(IReadOnlyList<IRunnerReporter> reporters) * { * var executableName = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().GetLocalCodeBase()); * * // NET Core * ////var executableName = "dotnet xunit"; * * Console.WriteLine("Copyright (C) .NET Foundation."); * Console.WriteLine(); * Console.WriteLine($"usage: {executableName} <assemblyFile> [configFile] [assemblyFile [configFile]...] [options] [reporter] [resultFormat filename [...]]"); * Console.WriteLine(); #if NET452 * Console.WriteLine("Note: Configuration files must end in .json (for JSON) or .config (for XML)"); #else * Console.WriteLine("Note: Configuration files must end in .json (XML is not supported on .NET Core)"); #endif * Console.WriteLine(); * Console.WriteLine("Valid options:"); * Console.WriteLine(" -nologo : do not show the copyright message"); * Console.WriteLine(" -nocolor : do not output results with colors"); #if NET452 * Console.WriteLine(" -noappdomain : do not use app domains to run test code"); #endif * Console.WriteLine(" -failskips : convert skipped tests into failures"); * Console.WriteLine(" -stoponfail : stop on first test failure"); * Console.WriteLine(" -parallel option : set parallelization based on option"); * Console.WriteLine(" : none - turn off all parallelization"); * Console.WriteLine(" : collections - only parallelize collections"); * Console.WriteLine(" : assemblies - only parallelize assemblies"); * Console.WriteLine(" : all - parallelize assemblies & collections"); * Console.WriteLine(" -maxthreads count : maximum thread count for collection parallelization"); * Console.WriteLine(" : default - run with default (1 thread per CPU thread)"); * Console.WriteLine(" : unlimited - run with unbounded thread count"); * Console.WriteLine(" : (number) - limit task thread pool size to 'count'"); #if NET452 * Console.WriteLine(" -noshadow : do not shadow copy assemblies"); #endif * Console.WriteLine(" -wait : wait for input after completion"); * Console.WriteLine(" -diagnostics : enable diagnostics messages for all test assemblies"); * Console.WriteLine(" -internaldiagnostics : enable internal diagnostics messages for all test assemblies"); #if DEBUG * Console.WriteLine(" -pause : pause before doing any work, to help attach a debugger"); #endif * Console.WriteLine(" -debug : launch the debugger to debug the tests"); * Console.WriteLine(" -serialize : serialize all test cases (for diagnostic purposes only)"); * Console.WriteLine(" -trait \"name=value\" : only run tests with matching name/value traits"); * Console.WriteLine(" : if specified more than once, acts as an OR operation"); * Console.WriteLine(" -notrait \"name=value\" : do not run tests with matching name/value traits"); * Console.WriteLine(" : if specified more than once, acts as an AND operation"); * Console.WriteLine(" -method \"name\" : run a given test method (can be fully specified or use a wildcard;"); * Console.WriteLine(" : i.e., 'MyNamespace.MyClass.MyTestMethod' or '*.MyTestMethod')"); * Console.WriteLine(" : if specified more than once, acts as an OR operation"); * Console.WriteLine(" -class \"name\" : run all methods in a given test class (should be fully"); * Console.WriteLine(" : specified; i.e., 'MyNamespace.MyClass')"); * Console.WriteLine(" : if specified more than once, acts as an OR operation"); * Console.WriteLine(" -namespace \"name\" : run all methods in a given namespace (i.e.,"); * Console.WriteLine(" : 'MyNamespace.MySubNamespace')"); * Console.WriteLine(" : if specified more than once, acts as an OR operation"); * Console.WriteLine(" -noautoreporters : do not allow reporters to be auto-enabled by environment"); * Console.WriteLine(" : (for example, auto-detecting TeamCity or AppVeyor)"); #if NETCOREAPP1_0 || NETCOREAPP2_0 * Console.WriteLine(" -framework \"name\" : set the target framework"); #endif * Console.WriteLine(); * * var switchableReporters = reporters.Where(r => !string.IsNullOrWhiteSpace(r.RunnerSwitch)).ToList(); * if (switchableReporters.Count > 0) * { * Console.WriteLine("Reporters: (optional, choose only one)"); * * foreach (var reporter in switchableReporters.OrderBy(r => r.RunnerSwitch)) * { * Console.WriteLine($" -{reporter.RunnerSwitch.ToLowerInvariant().PadRight(21)} : {reporter.Description}"); * } * * Console.WriteLine(); * } * * Console.WriteLine("Result formats: (optional, choose one or more)"); * TransformFactory.AvailableTransforms.ForEach( * transform => Console.WriteLine($" -{$"{transform.CommandLine} <filename>".PadRight(21).Substring(0, 21)} : {transform.Description}") * ); * } */ private int RunProject([NotNull] TestRunOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } XunitProject project = options.Project; bool?parallelizeAssemblies = options.ParallelizeAssemblies; XElement assembliesElement = null; var clockTime = Stopwatch.StartNew(); var xmlTransformers = TransformFactory.GetXmlTransformers(project); var needsXml = xmlTransformers.Count > 0; if (!parallelizeAssemblies.HasValue) { parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault); } if (needsXml) { assembliesElement = new XElement("assemblies"); } var originalWorkingFolder = Directory.GetCurrentDirectory(); if (parallelizeAssemblies.GetValueOrDefault()) { var tasks = project.Assemblies.Select( assembly => Task.Run( () => ExecuteAssembly( assembly, options, needsXml, project.Filters))); var results = Task.WhenAll(tasks).GetAwaiter().GetResult(); if (assembliesElement != null) { foreach (var assemblyElement in results.Where(result => result != null)) { assembliesElement.Add(assemblyElement); } } } else { foreach (var assembly in project.Assemblies) { var assemblyElement = ExecuteAssembly( assembly, options, needsXml, project.Filters); assembliesElement?.Add(assemblyElement); } } clockTime.Stop(); assembliesElement?.Add(new XAttribute("timestamp", DateTime.Now.ToString(CultureInfo.InvariantCulture))); if (_completionMessages.Count > 0) { _reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, _completionMessages.OrderBy(kvp => kvp.Key).ToList())); } Directory.SetCurrentDirectory(originalWorkingFolder); xmlTransformers.ForEach(transformer => transformer(assembliesElement)); return(_failed ? 1 : _completionMessages.Values.Sum(summary => summary.Failed)); }