Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ internal set
/// <summary>
/// Gets or sets the assembly initialization exception.
/// </summary>
public Exception? AssemblyInitializationException { get; internal set; }
public TestFailedException? AssemblyInitializationException { get; internal set; }

/// <summary>
/// Gets the assembly cleanup exception.
Expand All @@ -110,15 +110,19 @@ internal set
/// <summary>
/// Runs assembly initialize method.
/// </summary>
/// <param name="testContext"> The test context. </param>
/// <exception cref="TestFailedException"> Throws a test failed exception if the initialization method throws an exception. </exception>
public async Task RunAssemblyInitializeAsync(TestContext testContext)
/// <param name="testContext">The test context.</param>
/// <returns>
/// A <see cref="TestResult"/> whose <see cref="TestResult.Outcome"/> is <see cref="UnitTestOutcome.Passed"/>
/// when the assembly initialization succeeds, or the failure outcome with
/// <see cref="TestResult.TestFailureException"/> set when the initialization fails.
/// </returns>
public async Task<TestResult> RunAssemblyInitializeAsync(TestContext testContext)
{
// No assembly initialize => nothing to do.
if (AssemblyInitializeMethod == null)
{
IsAssemblyInitializeExecuted = true;
return;
return new TestResult { Outcome = UnitTestOutcome.Passed };
}

// If assembly initialization is not done, then do it.
Expand Down Expand Up @@ -161,7 +165,7 @@ public async Task RunAssemblyInitializeAsync(TestContext testContext)
}
catch (Exception ex)
{
AssemblyInitializationException = ex;
AssemblyInitializationException = GetTestFailedExceptionFromAssemblyInitializeException(ex, AssemblyInitializeMethod);
}
finally
{
Expand All @@ -176,37 +180,30 @@ public async Task RunAssemblyInitializeAsync(TestContext testContext)
}

// If assemblyInitialization was successful, then don't do anything
if (AssemblyInitializationException == null)
{
return;
}

// If the exception is already a `TestFailedException` we throw it as-is
if (AssemblyInitializationException is TestFailedException)
{
throw AssemblyInitializationException;
}
return AssemblyInitializationException is null
? new TestResult { Outcome = UnitTestOutcome.Passed }
: new TestResult { TestFailureException = AssemblyInitializationException, Outcome = AssemblyInitializationException.Outcome };
}

Exception realException = AssemblyInitializationException.GetRealException();
private static TestFailedException GetTestFailedExceptionFromAssemblyInitializeException(Exception ex, MethodInfo assemblyInitializeMethod)
{
Exception realException = ex.GetRealException();

UnitTestOutcome outcome = realException is AssertInconclusiveException ? UnitTestOutcome.Inconclusive : UnitTestOutcome.Failed;

// Do not use StackTraceHelper.GetFormattedExceptionMessage(realException) as it prefixes the message with the exception type name.
string exceptionMessage = realException.TryGetMessage();
DebugEx.Assert(AssemblyInitializeMethod.DeclaringType?.FullName is not null, "AssemblyInitializeMethod.DeclaringType.FullName is null");
DebugEx.Assert(assemblyInitializeMethod.DeclaringType?.FullName is not null, "AssemblyInitializeMethod.DeclaringType.FullName is null");
string errorMessage = string.Format(
CultureInfo.CurrentCulture,
Resource.UTA_AssemblyInitMethodThrows,
AssemblyInitializeMethod.DeclaringType.FullName,
AssemblyInitializeMethod.Name,
assemblyInitializeMethod.DeclaringType.FullName,
assemblyInitializeMethod.Name,
realException.GetType().ToString(),
exceptionMessage);
StackTraceInformation? exceptionStackTraceInfo = realException.GetStackTraceInformation();

var testFailedException = new TestFailedException(outcome, errorMessage, exceptionStackTraceInfo, realException);
AssemblyInitializationException = testFailedException;

throw testFailedException;
return new TestFailedException(outcome, errorMessage, exceptionStackTraceInfo, realException);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,15 +244,11 @@ internal async Task<TestResult[]> RunSingleTestAsync(UnitTestElement unitTestEle

private static async Task<TestResult> RunAssemblyInitializeIfNeededAsync(TestMethodInfo testMethodInfo, ITestContext testContext)
{
var result = new TestResult { Outcome = UnitTestOutcome.Passed };
TestResult? result = null;

try
{
await testMethodInfo.Parent.Parent.RunAssemblyInitializeAsync(testContext.Context).ConfigureAwait(false);
}
catch (TestFailedException ex)
{
result = new TestResult { TestFailureException = ex, Outcome = ex.Outcome };
result = await testMethodInfo.Parent.Parent.RunAssemblyInitializeAsync(testContext.Context).ConfigureAwait(false);
}
catch (Exception ex)
{
Expand All @@ -262,7 +258,7 @@ private static async Task<TestResult> RunAssemblyInitializeIfNeededAsync(TestMet
finally
{
var testContextImpl = testContext.Context as TestContextImplementation;
result.LogOutput = testContextImpl?.GetOut();
result!.LogOutput = testContextImpl?.GetOut();
result.LogError = testContextImpl?.GetErr();
result.DebugTrace = testContextImpl?.GetTrace();
result.TestContextMessages = testContext.GetAndClearDiagnosticMessages();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void Action()
public void TestAssemblyHasExecutableCleanupMethodShouldReturnTrueEvenIfAssemblyInitializationThrewAnException()
{
_testAssemblyInfo.AssemblyCleanupMethod = _dummyMethodInfo;
_testAssemblyInfo.AssemblyInitializationException = new NotImplementedException();
_testAssemblyInfo.AssemblyInitializationException = new TestFailedException(UnitTestOutcome.Error, "ERROR");

_testAssemblyInfo.HasExecutableCleanupMethod.Should().BeTrue();
}
Expand All @@ -79,9 +79,10 @@ public async Task RunAssemblyInitializeShouldNotInvokeIfAssemblyInitializeIsNull

_testAssemblyInfo.AssemblyInitializeMethod = null;

await _testAssemblyInfo.RunAssemblyInitializeAsync(null!);
TestResult result = await _testAssemblyInfo.RunAssemblyInitializeAsync(null!);

assemblyInitCallCount.Should().Be(0);
result.Outcome.Should().Be(UnitTestOutcome.Passed);
}

public async Task RunAssemblyInitializeShouldNotExecuteAssemblyInitializeIfItHasAlreadyExecuted()
Expand All @@ -92,9 +93,10 @@ public async Task RunAssemblyInitializeShouldNotExecuteAssemblyInitializeIfItHas
_testAssemblyInfo.IsAssemblyInitializeExecuted = true;
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);
TestResult result = await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);

assemblyInitCallCount.Should().Be(0);
result.Outcome.Should().Be(UnitTestOutcome.Passed);
}

public async Task RunAssemblyInitializeShouldExecuteAssemblyInitialize()
Expand All @@ -103,9 +105,10 @@ public async Task RunAssemblyInitializeShouldExecuteAssemblyInitialize()
DummyTestClass.AssemblyInitializeMethodBody = _ => assemblyInitCallCount++;
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);
TestResult result = await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);

assemblyInitCallCount.Should().Be(1);
result.Outcome.Should().Be(UnitTestOutcome.Passed);
}

public async Task RunAssemblyInitializeShouldSetAssemblyInitializeExecutedFlag()
Expand All @@ -114,9 +117,10 @@ public async Task RunAssemblyInitializeShouldSetAssemblyInitializeExecutedFlag()

_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);
TestResult result = await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);

_testAssemblyInfo.IsAssemblyInitializeExecuted.Should().BeTrue();
result.Outcome.Should().Be(UnitTestOutcome.Passed);
}

public async Task RunAssemblyInitializeShouldSetAssemblyInitializationExceptionOnException()
Expand All @@ -126,9 +130,9 @@ public async Task RunAssemblyInitializeShouldSetAssemblyInitializationExceptionO
#pragma warning restore RS0030 // Do not use banned APIs
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

Func<Task> action = () => _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);

await action.Should().ThrowAsync<Exception>();
TestResult testResult = await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);
testResult.Should().NotBeNull();
testResult.TestFailureException.Should().NotBeNull();
_testAssemblyInfo.AssemblyInitializationException.Should().NotBeNull();
}

Expand All @@ -139,7 +143,8 @@ public async Task RunAssemblyInitializeShouldThrowTestFailedExceptionOnAssertion
#pragma warning restore RS0030 // Do not use banned APIs
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

TestFailedException exception = (await new Func<Task>(() => _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).Should().ThrowAsync<TestFailedException>()).Which;
var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException;
exception.Should().NotBeNull();
exception.Outcome.Should().Be(UnitTestOutcome.Failed);
exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.Fail failed. Test failure. Aborting test execution.");
exception.StackTraceInformation!.ErrorStackTrace.Should().Contain(
Expand All @@ -154,7 +159,8 @@ public async Task RunAssemblyInitializeShouldThrowTestFailedExceptionWithInconcl
#pragma warning restore RS0030 // Do not use banned APIs
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

TestFailedException exception = (await new Func<Task>(() => _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).Should().ThrowAsync<TestFailedException>()).Which;
var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException;
exception.Should().NotBeNull();
exception.Outcome.Should().Be(UnitTestOutcome.Inconclusive);
exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. Microsoft.VisualStudio.TestTools.UnitTesting.AssertInconclusiveException: Assert.Inconclusive failed. Test Inconclusive. Aborting test execution.");
exception.StackTraceInformation!.ErrorStackTrace.Should().Contain(
Expand All @@ -167,8 +173,8 @@ public async Task RunAssemblyInitializeShouldThrowTestFailedExceptionWithNonAsse
DummyTestClass.AssemblyInitializeMethodBody = tc => throw new ArgumentException("Some actualErrorMessage message", new InvalidOperationException("Inner actualErrorMessage message"));
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

TestFailedException exception = (await new Func<Task>(() => _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).Should().ThrowAsync<TestFailedException>()).Which;

var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException;
exception.Should().NotBeNull();
exception.Outcome.Should().Be(UnitTestOutcome.Failed);
exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. System.ArgumentException: Some actualErrorMessage message. Aborting test execution.");
exception.StackTraceInformation!.ErrorStackTrace.Should().Contain(
Expand All @@ -186,8 +192,8 @@ public async Task RunAssemblyInitializeShouldThrowTheInnerMostExceptionWhenThere
FailingStaticHelper.DoWork();
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

TestFailedException exception = (await new Func<Task>(() => _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).Should().ThrowAsync<TestFailedException>()).Which;

var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException;
exception.Should().NotBeNull();
exception.Outcome.Should().Be(UnitTestOutcome.Failed);
exception.Message.Should().Be("Assembly Initialization method Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Execution.TestAssemblyInfoTests+DummyTestClass.AssemblyInitializeMethod threw exception. System.InvalidOperationException: I fail.. Aborting test execution.");
exception.StackTraceInformation!.ErrorStackTrace.StartsWith(
Expand All @@ -202,17 +208,25 @@ public async Task RunAssemblyInitializeShouldThrowForAlreadyExecutedTestAssembly
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;
_testAssemblyInfo.AssemblyInitializationException = new TestFailedException(UnitTestOutcome.Failed, "Cached Test failure");

TestFailedException exception = (await new Func<Task>(() => _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).Should().ThrowAsync<TestFailedException>()).Which;
var exception = (await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext)).TestFailureException as TestFailedException;
exception.Should().NotBeNull();
exception.Outcome.Should().Be(UnitTestOutcome.Failed);
exception.Message.Should().Be("Cached Test failure");
}

public async Task RunAssemblyInitializeShouldPassOnTheTestContextToAssemblyInitMethod()
{
DummyTestClass.AssemblyInitializeMethodBody = tc => (tc == _testContext).Should().BeTrue();
bool hasExecuted = false;
DummyTestClass.AssemblyInitializeMethodBody = tc =>
{
(tc == _testContext).Should().BeTrue();
hasExecuted = true;
};
_testAssemblyInfo.AssemblyInitializeMethod = typeof(DummyTestClass).GetMethod("AssemblyInitializeMethod")!;

await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);
TestResult result = await _testAssemblyInfo.RunAssemblyInitializeAsync(_testContext);
hasExecuted.Should().BeTrue();
result.Outcome.Should().Be(UnitTestOutcome.Passed);
}

#endregion
Expand Down