// **************************************************************** // This is free software licensed under the NUnit license. You // may obtain a copy of the license as well as information regarding // copyright ownership at http://nunit.org/?p=license&r=2.4. // **************************************************************** namespace NUnit.Core { using System; using System.Text; /// /// The TestResult abstract class represents /// the result of a test and is used to /// communicate results across AppDomains. /// /// [Serializable] public abstract class TestResult { #region Fields /// /// Indicates whether the test was executed or not /// private RunState runState; /// /// Indicates the result of the test /// private ResultState resultState; /// /// Indicates the location of a failure /// private FailureSite failureSite; /// /// The elapsed time for executing this test /// private double time = 0.0; /// /// The name of the test /// private string name; /// /// The test that this result pertains to /// private TestInfo test; /// /// The stacktrace at the point of failure /// private string stackTrace; /// /// Description of this test /// private string description; /// /// Message giving the reason for failure /// protected string messageString; /// /// Number of asserts executed by this test /// private int assertCount = 0; #endregion #region Protected Constructor /// /// Protected constructor constructs a test result given /// a test and a name. /// /// The test to be used /// Name for this result protected TestResult(TestInfo test, string name) { this.name = name; this.test = test; this.RunState = RunState.Runnable; if (test != null) { this.description = test.Description; this.runState = test.RunState; this.messageString = test.IgnoreReason; } } #endregion #region Properties /// /// Gets the RunState of the result, which indicates /// whether or not it has executed and why. /// public RunState RunState { get { return runState; } set { runState = value; } } /// /// Gets the ResultState of the test result, which /// indicates the success or failure of the test. /// public ResultState ResultState { get { return resultState; } } /// /// Gets the stage of the test in which a failure /// or error occured. /// public FailureSite FailureSite { get { return failureSite; } } /// /// Indicates whether the test executed /// public bool Executed { get { return runState == RunState.Executed; } } /// /// Gets the name of the test result /// public virtual string Name { get { return name; } } /// /// Gets the test associated with this result /// public ITest Test { get { return test; } } /// /// Indicates whether the test ran successfully /// public virtual bool IsSuccess { // TODO: Redefine this more precisely get { return !IsFailure; } //get { return resultState == ResultState.Success; } } /// /// Indicates whether the test failed /// // TODO: Distinguish errors from failures public virtual bool IsFailure { get { return resultState == ResultState.Failure || resultState == ResultState.Error; } } /// /// Gets a description associated with the test /// public virtual string Description { get { return description; } set { description = value; } } /// /// Gets the elapsed time for running the test /// public double Time { get { return time; } set { time = value; } } /// /// Gets the message associated with a test /// failure or with not running the test /// public string Message { get { return messageString; } } /// /// Gets any stacktrace associated with an /// error or failure. /// public virtual string StackTrace { get { return stackTrace; } set { stackTrace = value; } } /// /// Gets or sets the count of asserts executed /// when running the test. /// public int AssertCount { get { return assertCount; } set { assertCount = value; } } #endregion #region Public Methods /// /// Mark the test as succeeding /// public void Success() { this.runState = RunState.Executed; this.resultState = ResultState.Success; } /// /// Mark the test as ignored. /// /// The reason the test was not run public void Ignore(string reason) { Ignore( reason, null ); } /// /// Mark the test as ignored. /// /// The ignore exception that was thrown public void Ignore( Exception ex ) { Ignore( ex.Message, BuildStackTrace( ex ) ); } /// /// Mark the test as ignored. /// /// The reason the test was not run /// Stack trace giving the location of the command public void Ignore(string reason, string stackTrace) { NotRun( RunState.Ignored, reason, stackTrace ); } /// /// Mark the test as skipped. /// /// The reason the test was not run public void Skip(string reason) { Skip( reason, null ); } /// /// Mark the test as ignored. /// /// The ignore exception that was thrown public void Skip( Exception ex ) { Skip( ex.Message, BuildStackTrace( ex ) ); } /// /// Mark the test as skipped. /// /// The reason the test was not run /// Stack trace giving the location of the command public void Skip(string reason, string stackTrace) { NotRun( RunState.Skipped, reason, stackTrace ); } /// /// Mark the test as Not Run - either skipped or ignored /// /// The RunState to use in the result /// The reason the test was not run /// Stack trace giving the location of the command public void NotRun(RunState runState, string reason, string stackTrace) { this.runState = runState; this.messageString = reason; this.stackTrace = stackTrace; } /// /// Mark the test as a failure due to an /// assertion having failed. /// /// Message to display /// Stack trace giving the location of the failure public void Failure(string message, string stackTrace) { Failure(message, stackTrace, FailureSite.Test); } /// /// Mark the test as a failure due to an /// assertion having failed. /// /// Message to display /// Stack trace giving the location of the failure /// The site of the failure public void Failure(string message, string stackTrace, FailureSite failureSite ) { this.runState = RunState.Executed; this.resultState = ResultState.Failure; this.failureSite = failureSite; this.messageString = message; this.stackTrace = stackTrace; } /// /// Marks the result as an error due to an exception thrown /// by the test. /// /// The exception that was caught public void Error(Exception exception) { Error(exception, FailureSite.Test); } /// /// Marks the result as an error due to an exception thrown /// from the indicated FailureSite. /// /// The exception that was caught /// The site from which it was thrown public void Error( Exception exception, FailureSite failureSite ) { this.runState = RunState.Executed; this.resultState = ResultState.Error; this.failureSite = failureSite; string message = BuildMessage(exception); string stackTrace = BuildStackTrace(exception); if (failureSite == FailureSite.TearDown) { message = "TearDown : " + message; stackTrace = "--TearDown" + Environment.NewLine + stackTrace; if (this.messageString != null) message = this.messageString + Environment.NewLine + message; if (this.stackTrace != null) stackTrace = this.stackTrace + Environment.NewLine + stackTrace; } this.messageString = message; this.stackTrace = stackTrace; } #endregion #region Exception Helpers private string BuildMessage(Exception exception) { StringBuilder sb = new StringBuilder(); sb.AppendFormat( "{0} : {1}", exception.GetType().ToString(), exception.Message ); Exception inner = exception.InnerException; while( inner != null ) { sb.Append( Environment.NewLine ); sb.AppendFormat( " ----> {0} : {1}", inner.GetType().ToString(), inner.Message ); inner = inner.InnerException; } return sb.ToString(); } private string BuildStackTrace(Exception exception) { StringBuilder sb = new StringBuilder( GetStackTrace( exception ) ); Exception inner = exception.InnerException; while( inner != null ) { sb.Append( Environment.NewLine ); sb.Append( "--" ); sb.Append( inner.GetType().Name ); sb.Append( Environment.NewLine ); sb.Append( GetStackTrace( inner ) ); inner = inner.InnerException; } return sb.ToString(); } private string GetStackTrace(Exception exception) { try { return exception.StackTrace; } catch( Exception ) { return "No stack trace available"; } } #endregion /// /// Abstract method that accepts a ResultVisitor /// /// The visitor public abstract void Accept(ResultVisitor visitor); } }