in src/Adapter/MSTest.CoreAdapter/Execution/TestMethodInfo.cs [250:348]
private TestResult ExecuteInternal(object[] arguments)
{
Debug.Assert(this.TestMethod != null, "UnitTestExecuter.DefaultTestMethodInvoke: testMethod = null.");
var result = new TestResult();
// TODO remove dry violation with TestMethodRunner
var classInstance = this.CreateTestClassInstance(result);
var testContextSetup = false;
bool isExceptionThrown = false;
bool hasTestInitializePassed = false;
Exception testRunnerException = null;
try
{
try
{
if (classInstance != null && this.SetTestContext(classInstance, result))
{
// For any failure after this point, we must run TestCleanup
testContextSetup = true;
if (this.RunTestInitializeMethod(classInstance, result))
{
hasTestInitializePassed = true;
PlatformServiceProvider.Instance.ThreadOperations.ExecuteWithAbortSafety(
() => this.TestMethod.InvokeAsSynchronousTask(classInstance, arguments));
result.Outcome = TestTools.UnitTesting.UnitTestOutcome.Passed;
}
}
}
catch (Exception ex)
{
isExceptionThrown = true;
if (this.IsExpectedException(ex, result))
{
// Expected Exception was thrown, so Pass the test
result.Outcome = TestTools.UnitTesting.UnitTestOutcome.Passed;
}
else if (result.TestFailureException == null)
{
// This block should not throw. If it needs to throw, then handling of
// ThreadAbortException will need to be revisited. See comment in RunTestMethod.
result.TestFailureException = this.HandleMethodException(
ex,
this.TestClassName,
this.TestMethodName);
}
if (result.Outcome != TestTools.UnitTesting.UnitTestOutcome.Passed)
{
if (ex is UTF.AssertInconclusiveException || ex.InnerException is UTF.AssertInconclusiveException)
{
result.Outcome = TestTools.UnitTesting.UnitTestOutcome.Inconclusive;
}
else
{
result.Outcome = TestTools.UnitTesting.UnitTestOutcome.Failed;
}
}
}
// if we get here, the test method did not throw the exception
// if the user specified that the test was going to throw an exception, and
// it did not, we should fail the test
// We only perform this check if the test initialize passes and the test method is actually run.
if (hasTestInitializePassed && !isExceptionThrown && this.TestMethodOptions.ExpectedException != null)
{
result.TestFailureException = new TestFailedException(
UnitTestOutcome.Failed,
this.TestMethodOptions.ExpectedException.NoExceptionMessage);
result.Outcome = TestTools.UnitTesting.UnitTestOutcome.Failed;
}
}
catch (Exception exception)
{
testRunnerException = exception;
}
// Set the current tests outcome before cleanup so it can be used in the cleanup logic.
this.TestMethodOptions.TestContext.SetOutcome(result.Outcome);
// TestCleanup can potentially be a long running operation which shouldn't ideally be in a finally block.
// Pulling it out so extension writers can abort custom cleanups if need be. Having this in a finally block
// does not allow a thread abort exception to be raised within the block but throws one after finally is executed
// crashing the process. This was blocking writing an extension for Dynamic Timeout in VSO.
if (classInstance != null && testContextSetup)
{
this.RunTestCleanupMethod(classInstance, result);
}
if (testRunnerException != null)
{
throw testRunnerException;
}
return result;
}