/// <summary> /// Initializes a new instance of the <see cref="LogMessageListener"/> class. /// </summary> /// <param name="captureDebugTraces">Captures debug traces if true.</param> public LogMessageListener(bool captureDebugTraces) { this.captureDebugTraces = captureDebugTraces; // Cache the original output/error streams and replace it with the own stream. this.redirectLoggerOut = new ThreadSafeStringWriter(CultureInfo.InvariantCulture); this.redirectStdErr = new ThreadSafeStringWriter(CultureInfo.InvariantCulture); Logger.OnLogMessage += this.redirectLoggerOut.WriteLine; // Cache the previous redirector if any and replace the trace listener. this.previousRedirector = activeRedirector; if (this.captureDebugTraces) { this.traceListener = PlatformServiceProvider.Instance.GetTraceListener(new ThreadSafeStringWriter(CultureInfo.InvariantCulture)); this.traceListenerManager = PlatformServiceProvider.Instance.GetTraceListenerManager(this.redirectLoggerOut, this.redirectStdErr); // If there was a previous LogMessageListener active, remove its // TraceListener (it will be restored when this one is disposed). if (this.previousRedirector != null && this.previousRedirector.traceListener != null) { this.traceListenerManager.Remove(this.previousRedirector.traceListener); } this.traceListenerManager.Add(this.traceListener); } activeRedirector = this; }
/// <summary> /// Runs the class cleanup method. /// It returns any error information during the execution of the cleanup method /// </summary> /// <returns> The <see cref="RunCleanupResult"/>. </returns> internal RunCleanupResult RunCleanup() { // No cleanup methods to execute, then return. var assemblyInfoCache = this.typeCache.AssemblyInfoListWithExecutableCleanupMethods; var classInfoCache = this.typeCache.ClassInfoListWithExecutableCleanupMethods; if (!assemblyInfoCache.Any() && !classInfoCache.Any()) { return(null); } var result = new RunCleanupResult { Warnings = new List <string>() }; using (var redirector = new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces)) { try { this.RunClassCleanupMethods(classInfoCache, result.Warnings); this.RunAssemblyCleanup(assemblyInfoCache, result.Warnings); } finally { // Replacing the null character with a string.replace should work. // If this does not work for a specific dotnet version a custom function doing the same needs to be put in place. result.StandardOut = redirector.GetAndClearStandardOutput()?.Replace("\0", "\\0"); result.StandardError = redirector.GetAndClearStandardError()?.Replace("\0", "\\0"); result.DebugTrace = redirector.GetAndClearDebugTrace()?.Replace("\0", "\\0"); } } return(result); }
internal UnitTestResult[] Execute() { string initLogs = string.Empty; string initTrace = string.Empty; string errorLogs = string.Empty; UnitTestResult[] result = null; try { using (LogMessageListener logListener = new LogMessageListener(this.captureDebugTraces)) { try { // Run the assembly and class Initialize methods if required. // Assembly or class initialize can throw exceptions in which case we need to ensure that we fail the test. this.testMethodInfo.Parent.Parent.RunAssemblyInitialize(this.testContext.Context); this.testMethodInfo.Parent.RunClassInitialize(this.testContext.Context); } finally { initLogs = logListener.StandardOutput; initTrace = logListener.DebugTrace; errorLogs = logListener.StandardError; } } // Listening to log messages when running the test method with its Test Initialize and cleanup later on in the stack. // This allows us to differentiate logging when data driven methods are used. result = this.RunTestMethod(); } catch (TestFailedException ex) { result = new[] { new UnitTestResult(ex) }; } catch (Exception ex) { if (result == null || result.Length == 0) { result = new[] { new UnitTestResult() }; } var newResult = new UnitTestResult(new TestFailedException(UnitTestOutcome.Error, ex.TryGetMessage(), ex.TryGetStackTraceInformation())); newResult.StandardOut = result[result.Length - 1].StandardOut; newResult.StandardError = result[result.Length - 1].StandardError; newResult.DebugTrace = result[result.Length - 1].DebugTrace; newResult.Duration = result[result.Length - 1].Duration; result[result.Length - 1] = newResult; } finally { var firstResult = result[0]; firstResult.StandardOut = initLogs + firstResult.StandardOut; firstResult.StandardError = errorLogs + firstResult.StandardError; firstResult.DebugTrace = initTrace + firstResult.DebugTrace; } return(result); }
/// <summary> /// Execute test method. Capture failures, handle async and return result. /// </summary> /// <param name="arguments"> /// Arguments to pass to test method. (E.g. For data driven) /// </param> /// <returns>Result of test method invocation.</returns> public virtual TestResult Invoke(object[] arguments) { Stopwatch watch = new Stopwatch(); TestResult result = null; // check if arguments are set for data driven tests if (arguments == null) { arguments = this.Arguments; } using (LogMessageListener listener = new LogMessageListener(this.TestMethodOptions.CaptureDebugTraces)) { var testElement = new UnitTestElement(new TestMethod(this)) { TestId = this.TestId }; watch.Start(); try { this.TestExecutionRecorder.RecordStart(testElement); if (this.IsTimeoutSet) { result = this.ExecuteInternalWithTimeout(arguments); } else { result = this.ExecuteInternal(arguments); } } finally { // Handle logs & debug traces. watch.Stop(); if (result != null) { result.Duration = watch.Elapsed; result.DebugTrace = listener.DebugTrace; result.LogOutput = listener.StandardOutput; result.LogError = listener.StandardError; result.TestContextMessages = this.TestMethodOptions.TestContext.GetAndClearDiagnosticMessages(); result.ResultFiles = this.TestMethodOptions.TestContext.GetResultFiles(); result.TestId = this.TestId; } this.TestExecutionRecorder.RecordEnd( testElement, result?.Outcome.ToUnitTestOutcome() ?? UnitTestOutcome.Error); } } return(result); }
private void Dispose(bool disposing) { if (disposing) { Logger.OnLogMessage -= this.redirectLoggerOut.WriteLine; Logger.OnLogMessage -= this.redirectStdErr.WriteLine; this.redirectLoggerOut.Dispose(); this.redirectStdErr.Dispose(); if (this.captureDebugTraces) { try { if (this.traceListener != null) { this.traceListenerManager.Remove(this.traceListener); } // Restore the previous LogMessageListener's TraceListener (if there was one) if (this.previousRedirector != null && this.previousRedirector.traceListener != null) { this.traceListenerManager.Add(this.previousRedirector.traceListener); } } catch (Exception e) { // Catch all exceptions since Dispose should not throw. PlatformServiceProvider.Instance.AdapterTraceLogger.LogError( "ConsoleOutputRedirector.Dispose threw exception: {0}", e); } if (this.traceListener != null) { // Dispose trace manager and listeners this.traceListenerManager.Dispose(this.traceListener); this.traceListenerManager = null; this.traceListener = null; } } activeRedirector = this.previousRedirector; } }
/// <summary> /// Execute test method. Capture failures, handle async and return result. /// </summary> /// <param name="arguments"> /// Arguments to pass to test method. (E.g. For data driven) /// </param> /// <returns>Result of test method invocation.</returns> public virtual TestResult Invoke(object[] arguments) { Stopwatch watch = new Stopwatch(); TestResult result = null; // check if arguments are set for data driven tests if (arguments == null) { arguments = this.Arguments; } using (LogMessageListener listener = new LogMessageListener(this.TestMethodOptions.CaptureDebugTraces)) { watch.Start(); try { if (this.IsTimeoutSet) { result = this.ExecuteInternalWithTimeout(arguments); } else { result = this.ExecuteInternal(arguments); } } finally { // Handle logs & debug traces. watch.Stop(); if (result != null) { result.Duration = watch.Elapsed; result.DebugTrace = listener.GetAndClearDebugTrace(); result.LogOutput = listener.GetAndClearStandardOutput(); result.LogError = listener.GetAndClearStandardError(); result.TestContextMessages = this.TestMethodOptions.TestContext.GetAndClearDiagnosticMessages(); result.ResultFiles = this.TestMethodOptions.TestContext.GetResultFiles(); } } } return(result); }
private void RunClassCleanupIfEndOfClass(TestMethodInfo testMethodInfo, TestMethod testMethod, UnitTestResult[] results) { bool shouldRunClassCleanup = false; this.classCleanupManager?.MarkTestComplete(testMethodInfo, testMethod, out shouldRunClassCleanup); if (shouldRunClassCleanup) { string cleanupLogs = string.Empty; string cleanupTrace = string.Empty; string cleanupErrorLogs = string.Empty; try { using (LogMessageListener logListener = new LogMessageListener(MSTestSettings.CurrentSettings.CaptureDebugTraces)) { try { // Class cleanup can throw exceptions in which case we need to ensure that we fail the test. testMethodInfo.Parent.RunClassCleanup(ClassCleanupBehavior.EndOfClass); } finally { cleanupLogs = logListener.StandardOutput; cleanupTrace = logListener.DebugTrace; cleanupErrorLogs = logListener.StandardError; var lastResult = results[results.Length - 1]; lastResult.StandardOut = lastResult.StandardOut + cleanupLogs; lastResult.StandardError = lastResult.StandardError + cleanupErrorLogs; lastResult.DebugTrace = lastResult.DebugTrace + cleanupTrace; } } } catch (Exception e) { results[results.Length - 1].Outcome = ObjectModel.UnitTestOutcome.Failed; results[results.Length - 1].ErrorMessage = e.Message; results[results.Length - 1].ErrorStackTrace = e.StackTrace; } } }
/// <inheritdoc/> /// <remarks> /// Execute test method. Capture failures, handle async and return result. /// </remarks> public virtual TestResult Invoke(object[] arguments) { Stopwatch watch = new Stopwatch(); TestResult result = null; using (LogMessageListener listener = new LogMessageListener(this.TestMethodOptions.CaptureDebugTraces)) { watch.Start(); try { if (this.IsTimeoutSet) { result = this.ExecuteInternalWithTimeout(arguments); } else { result = this.ExecuteInternal(arguments); } } finally { // Handle logs & debug traces. watch.Stop(); if (result != null) { result.Duration = watch.Elapsed; result.DebugTrace = listener.DebugTrace; result.LogOutput = listener.StandardOutput; result.LogError = listener.StandardError; result.ResultFiles = this.TestMethodOptions.TestContext.GetResultFiles(); } } } return(result); }
internal UnitTestResult[] Execute() { string initLogs = string.Empty; string initTrace = string.Empty; string initErrorLogs = string.Empty; string inittestContextMessages = string.Empty; UnitTestResult[] result = null; string ignoreMessage = null; var isIgnoreAttributeOnClass = this.reflectHelper.IsAttributeDefined(this.testMethodInfo.Parent.ClassType, typeof(UTF.IgnoreAttribute), false); var isIgnoreAttributeOnMethod = this.reflectHelper.IsAttributeDefined(this.testMethodInfo.TestMethod, typeof(UTF.IgnoreAttribute), false); if (isIgnoreAttributeOnClass) { ignoreMessage = this.reflectHelper.GetIgnoreMessage(this.testMethodInfo.Parent.ClassType.GetTypeInfo()); } if (string.IsNullOrEmpty(ignoreMessage) && isIgnoreAttributeOnMethod) { ignoreMessage = this.reflectHelper.GetIgnoreMessage(this.testMethodInfo.TestMethod); } if (isIgnoreAttributeOnClass || isIgnoreAttributeOnMethod) { return(new[] { new UnitTestResult(UnitTestOutcome.Ignored, ignoreMessage) }); } try { using (LogMessageListener logListener = new LogMessageListener(this.captureDebugTraces)) { try { // Run the assembly and class Initialize methods if required. // Assembly or class initialize can throw exceptions in which case we need to ensure that we fail the test. this.testMethodInfo.Parent.Parent.RunAssemblyInitialize(this.testContext.Context); this.testMethodInfo.Parent.RunClassInitialize(this.testContext.Context); } finally { initLogs = logListener.StandardOutput; initTrace = logListener.DebugTrace; initErrorLogs = logListener.StandardError; inittestContextMessages = this.testContext.GetAndClearDiagnosticMessages(); } } // Listening to log messages when running the test method with its Test Initialize and cleanup later on in the stack. // This allows us to differentiate logging when data driven methods are used. result = this.RunTestMethod(); } catch (TestFailedException ex) { result = new[] { new UnitTestResult(ex) }; } catch (Exception ex) { if (result == null || result.Length == 0) { result = new[] { new UnitTestResult() }; } var newResult = new UnitTestResult(new TestFailedException(UnitTestOutcome.Error, ex.TryGetMessage(), ex.TryGetStackTraceInformation())); newResult.StandardOut = result[result.Length - 1].StandardOut; newResult.StandardError = result[result.Length - 1].StandardError; newResult.DebugTrace = result[result.Length - 1].DebugTrace; newResult.TestContextMessages = result[result.Length - 1].TestContextMessages; newResult.Duration = result[result.Length - 1].Duration; result[result.Length - 1] = newResult; } finally { var firstResult = result[0]; firstResult.StandardOut = initLogs + firstResult.StandardOut; firstResult.StandardError = initErrorLogs + firstResult.StandardError; firstResult.DebugTrace = initTrace + firstResult.DebugTrace; firstResult.TestContextMessages = inittestContextMessages + firstResult.TestContextMessages; } return(result); }