Skip to content

Add [StackTraceHidden] to all Assert/CollectionAssert/StringAssert APIs (post-RFC 012) #8277

@Evangelink

Description

@Evangelink

Background

Once the assertion refactorings for RFC 012 are complete, every public method on Assert, CollectionAssert, and StringAssert will already be touched. That is a good moment to annotate them with [StackTraceHidden] so the runtime omits MSTest framework frames from Exception.StackTrace on .NET 6+.

Doing this in a single pass after RFC 012 lands keeps the diff localized and avoids re-touching files later.

What

Add [StackTraceHidden] (TFM-gated for net6.0+; polyfill via internal attribute on older TFMs if desired but with no runtime effect) to:

  • All public methods on Microsoft.VisualStudio.TestTools.UnitTesting.Assert (and all its partial-class files: Assert.AreEqual.cs, Assert.IComparable.cs, Assert.IsNull.cs, Assert.Contains.cs, Assert.IsInstanceOfType.cs, Assert.ThrowsException.cs, Assert.That.cs, Assert.StartsWith.cs, Assert.Matches.cs, Assert.IsTrue.cs, Assert.AreSame.cs, Assert.Inconclusive.cs, Assert.Fail.cs, Assert.Count.cs, Assert.EndsWith.cs, …).
  • All public methods on CollectionAssert (and its partials: CollectionAssert.Membership.cs, CollectionAssert.Equivalence.cs, CollectionAssert.Equality.cs, CollectionAssert.Type.cs, CollectionAssert.Subset.cs, CollectionAssert.Helpers.cs).
  • All public methods on StringAssert.
  • Internal helpers that exclusively serve the assertion call path (StructuredAssertionMessage.Format, AssertionValueRenderer.*, AssertScope notification path, EvidenceBlock.Format, …) so the hidden span is contiguous.
  • Any Assert*Exception constructors that we want to hide as a frame.

Why

  • Fixes the AzDO reporter heuristic at the source. Today the AzureDevOpsReporter walks Exception.StackTrace looking for the first frame that isn't an assertion implementation, using a brittle filename heuristic (EndsWith("Assert.cs")) — see Assert.IComparable not compatible with AzDoReport extension #6925. With [StackTraceHidden], those frames are not produced by the CLR in the first place, so the reporter naturally points at user code.
  • Improves every other stack-trace consumer at the same time. Terminal reporter, IDE test explorer, TRX writer, and any third-party consumer all stop showing the framework's assertion internals.
  • Cleans up user-visible stacks. Users no longer see noise like at MSTest...Assert.AreEqual[T](T, T, String) above their own test code.
  • Language-agnostic. The runtime honors [StackTraceHidden] regardless of source language (C# / F# / VB).

Limitations

  • [StackTraceHidden] only takes effect on .NET 6+. On netstandard2.0 / .NET Framework consumers, the attribute is a no-op and stack frames remain visible. The reporter-side filename fix (separate issue) covers that case.

Acceptance

  • Every public assertion method on Assert / CollectionAssert / StringAssert carries [StackTraceHidden] on supported TFMs.
  • A test under Microsoft.Testing.Extensions.UnitTests (or TestFramework.UnitTests) verifies that an AssertFailedException thrown from a partial-class file (e.g., Assert.IComparable.cs, Assert.AreEqual.cs) does not include the framework frame in Exception.StackTrace on .NET 6+.
  • AzDO reporter test exercises a real assertion failure and asserts the annotation points at the test method file, not the framework file.

Sequencing

Blocked on completion of RFC 012 implementation so the changes stay in a single mechanical pass.

Related: #6925

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions