Table of Contents

Core Framework v3 3.0.0 2025 July 13

Today, we're shipping three new releases:

  • xUnit.net Core Framework v3 3.0.0
  • xUnit.net Analyzers 1.23.0 (release notes)
  • xUnit.net Visual Studio adapter 3.1.2 (release notes)

It's been 5 weeks since the release of 2.0.3.

As always, we'd like to thank all the users who contributed to the success of xUnit.net through usage, feedback, and code. 🎉

Release Notes

These release notes are a list of changes from 2.0.3 to 3.0.0.

This release contains breaking changes as indicated by the major version bump. Binary compatibility with 2.x.y packages is not guaranteed, and extensibility projects should verify whether these breaking changes affect them as they may be required to issue new versions.

Core Framework

  • We have added a new property Label to the theory data row classes and theory data attributes. Developers can set the Label property to influence the parameter display for test cases with theory data:

    • Unset (or set to null) will use the existing behavior: TestMethod(...parameters...)
    • Set to an empty string will remove the parameter list: TestMethod
    • Set to a non-empty string will add the label to the display name: TestMethod [LabelValue]

    This will be most commonly used when combined to either label tests with complex parameters with a simpler label, or remove the parameters when combined with custom display names that already include all the necessary information for differentiating theory data rows from one another. Note that if you set this value on both the data attribute and the data row, the value from the data row will take precedence. xunit/xunit#3300

  • We have added new properties (SkipType, SkipUnless, and SkipWhen) to the theory data row classes and theory data attributes. These mirror the properties that were already available on FactAttribute, and allow data rows to be conditionally skipped. Note that if you set these values on both the data attribute and the data row, the value from the data row will take precedence. xunit/xunit#3314

  • We have added a generic version of ClassDataAttribute so that you can replace [ClassData(typeof(MyData))] with [ClassData<MyData>]. Note that this is only supported on .NET, as .NET Framework does not support generic attributes. xunit/xunit#2945

  • When we try to create custom attributes and it fails, we are now logging these failures via diagnostic messages. Some cases where this is most likely to happen is while registering serializers (with [RegisterXunitSerializer]), creating test collection factories, creating BeforeAfterTestAttribute instances, creating test case/collection orderers, collecting traits, among others. These new warning messages come due to a change made to way attributes are constructed in 3.0.0-pre.25 in an attempt to make attribute constructor exceptions be less system-breaking.

  • We have added two overloads to TestContext.Current.AddAttachment to allow developers to overwrite an existing attachment. The existing overloads will continue to throw when attempting to add an attachment when one already exists with the given name. xunit/xunit#3340

  • Breaking change: The type of TestContext.Current.KeyValueStorage has changed:

    • 2.0.3: Dictionary<string, object?>
    • 3.0.0: ConcurrentDictionary<string, object?>

    This change was made to accommodate race conditions that could exist when reading or writing shared values from multiple tests and/or multiple extensibility points. xunit/xunit#3306

  • Breaking change: For v3 test projects, we have opted to use [CallerFilePath] and [CallerLineNumber] decorated onto FactAttribute and TheoryAttribute rather than CecilSourceInformationProvider. This should improve both performance and reliability for retrieving source location information. This is a binary breaking change only; there should be no compilation issues caused by these changes, as the new parameters are (by design) decorated with default values.

    Tests should not try to set these values manually as they will be provided automatically by the compiler. xunit/xunit#3304

  • Breaking change: We have decided to deprecate CecilSourceInformationProvider based on performance and compatibility issues.

    • v3 projects will utilize the compile-time source information available via [FactAttribute], introduced in 3.0.0-pre.15. This is used for all execution paths: xUnit.net native runners, Microsoft Testing Platform, and VSTest (aka xunit.runner.visualstudio).

    • v1/v2 projects will utilize DiaSession from VSTest. Source information will only be available for these projects when running in the context of VSTest. v1/v2 projects running in xUnit.net native runners will not include source information, and these projects do not support Microsoft Testing Platform.

  • Breaking change: To fix a bug with attributes throwing in their constructors, we have changed the way we discover attributes. This "new" behavior is actually a restoration of older behavior from v2, which was required by virtue of the way we opted to allow attributes to be discovered by interface instead of concrete type. While this code is based on well tested code from v2, it's being put into new use in v3, and there may be edge case issues surrounding attribute discovery owing to this implementation change. Developers relying upon ReflectionExtensions.GetMatchingCustomAttributes should test to ensure that no attribute lookup bugs in their extensions have been caused by this change. xunit/xunit#3319

  • BUG: We have fixed a memory leak in TestContext due to a CancellationTokenSource object which was being allocated but not disposed. xunit/xunit#3323

  • BUG: We have fixed an issue where the CaptureConsole and CaptureTrace attributes were not usable in some circumstances. xunit/xunit#3334

  • BUG: We have fixed an issue where F# modules with , in their name were causing parsing issues during type deserialization, causing them to be non-runnable in Visual Studio. xunit/xunit#3332

  • BUG: We have fixed an issue where it was possible for us to generate two Microsoft Testing Platform log files with the same filename in some rare conditions. xunit/xunit#3333

  • BUG: TestContext was not being properly disposed, which caused a memory leak of disposable objects it contains (in particular, the cancellation token sources). xunit/xunit#3323

Assertion Library

  • We have added new overloads to Assert.Throws which allow the developer to provide an exception inspector. The inspector lambda accepts the exception (typed as Exception in the non-generic versions, or typed as T in the generic versions), and can return true to accept the exception or false to reject the exception. You may also throw (including using assertions) inside the lambda if you wish. xunit/xunit#2154

  • Breaking change: We have removed an obsolete overload of CollectionTracker.AreCollectionsEqual. This was marked obsolete in 2.0.0 with a warning about being removed in the next major version.

  • BUG: We have fixed an issue with Assert.EquivalentWithExclusions where it would ignore properties too aggressively, leading to potential false positives. xunit/xunit#3338

Microsoft Testing Platform

Extensibility

  • Breaking change: We have added a new property (Label) to ITheoryDataRow and IDataAttribute.

  • Breaking change: We have added three new properties (SkipType, SkipUnless, and SkipWhen) to IDataAttribute, ITheoryDataRow, and IXunitTest. The constructor for XunitTest was updated to accommodate these new values.

  • Breaking change: We have added two new properties (SourceFilePath and SourceLineNumber) to IFactAttribute. The new FactAttribute constructor (mentioned above) sets these values.

    Any extensibility point which creates its own attributes derived (directly or indirectly) from FactAttribute will want to provide these same constructor arguments, or else source location information will be unavailable for tests decorated with such attributes. We have added an analyzer rule to detect this situation, since the compiler will not be helpful to discover the change.

  • Breaking change: The existing ExecutionErrorTestCase constructor has been marked as obsolete, replaced by a new constructor that includes two new parameters (sourceFilePath and sourceLineNumber). The old constructor will be removed in the next major release.

  • Breaking change: The existing TestIntrospectionHelper.GetTestCaseDetails has been marked as obsolete, replaced by a new overload that includes a new label parameter. The old overload will be removed in the next major version.

  • Breaking change: The return type from TestIntrospectionHelper methods GetTestCaseDetails and GetTestCaseDetailsForTheoryDataRow now include two new values in the unnamed tuple return value: SourceFilePath and SourceLineNumber.

  • Breaking change: We have added a new property (TestMethodArity) to ITestCaseMetadata and ITestMethodMetadata to support a new requirement from Microsoft Testing Platform 1.7 that requires method arity for test case metadata. This has a downstream impact on ITestCaseDiscovered, ITestCaseStarting, and ITestMethodStarting, as well as the classes which implement all of these interfaces.

    Note that arity will only be available for messages from v3 test projects; this information is not back-ported for v1 or v2, and will return as null. microsoft/testfx#5516

Runner Utility

  • We have bumped up the "crash detection" idle message timeout from 5 seconds to 60 seconds, to help eliminate potential false positives related to crashing when running tests on slower machines. This value can be changed by runners by setting XunitProject.Configuration.CrashDetectionSinkTimeout. This configuration value is not directly adjustable by end users at this time, and there should be no noticeable change in project execution time for test projects which aren't crashing.

  • Breaking change: We have deprecated the AssemblyRunner class (and all associated types) that live in the Xunit.Runners namespace, in favor of a new design that lives in the Xunit.SimpleRunner namespace. The v3 TestRunner Sample has been updated to use the new APIs. xunit/xunit#3265

    Notable changes include:

    • A new AssemblyRunnerOptions class is used to do all configuration of the assembly runner.

      This replaces the previous mixture of configuration that was spread out across the factory functions (WithoutAppDomain and WithAppDomain), the AssemblyRunner instance itself (for events), and the AssemblyRunnerStartOptions class (for configuration).

      Instead, you create AssemblyRunnerOptions with the path to the test assembly, and then you can configure it and subscribe to the events on it. It becomes a self-contained description of your intended test run. When constructed, the configuration options are pre-populated with values from the test assembly configuration (typically xunit.runner.json).

    • The AssemblyRunnerOptions includes a few new metadata properties: TargetFrameworkIdentifier (which target framework the test assembly was compiled against), TargetFrameworkVersion (which version of the target framework the test assembly was compiled for), and XunitVersion (which major version of xUnit.net the test assembly targets).

    • Configuration values in AssemblyRunnerOptions document which major versions of xUnit.net they support, and they will not only validate the values provided but also that setting the values will be meaningful. For example, if you try to set AssertEquivalentMaxDepth and your test assembly isn't targeting xUnit.net v3, then an exception will be thrown indicating this. Documentation example:

      AssemblyRunnerOptions XML doc comment for AssertEquivalentMaxDepth

    • There are three properties on AssemblyRunnerOptions that are only available when your runner is targeting .NET Framework and your test project is targeting .NET Framework using xUnit.net v1 or v2: AppDomain, ShadowCopy, and ShadowCopyFolder. These values replace the configuration available previously via WithAppDomain.

    • We have dramatically increased the number of available configuration options to be better aligned with all the options now available in v3.

    • Test filtering is now fully supported. The old lambda-based TestCaseFilter has been replaced by the Filters property on AssemblyRunnerOptions, which allows you to specify any of the typically available filtering options. This includes simple filters (like including/excluding based on class, method, namespace, etc.) as well query filters. Note: You may not mix simple filters with query filters. Use one or the other.

    • Most of the event information classes have been improved to include more information about the respective events. All the Finished event information includes the information from the related Starting event information so that you no longer need to track that information across the two events.

      We have also added two new events: OnDiscoveryStaring and OnExecutionStarting.

    • We have added support for generating one or more of the built-in reports (XML, HTML, CTRF, etc.) at the end of test execution. You can request reports by calling AddReport on the AssemblyRunnerOptions instance.

    • The old design offered a Start method which immediately returned, and required the developer to periodically poll the Status property to determine when test execution was complete. The new design replaces this with a Run method which returns Task. Developers should await the Task to determine when the execution is complete. Note: The AssemblyRunner cannot issue multiple simultaneous Run requests, though it can be reused after it's finished a previous run.

Packages

  • We have removed an MSBuild property (<IsTestProject>true</IsTestProject>) from the xunit.v3.core NuGet package, in anticipation of some changes that are being made by the VSTest team. dotnet/sdk#49063