FirstChanceGuard.Xunit 1.0.0

The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package FirstChanceGuard.Xunit --version 1.0.0
                    
NuGet\Install-Package FirstChanceGuard.Xunit -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FirstChanceGuard.Xunit" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FirstChanceGuard.Xunit" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="FirstChanceGuard.Xunit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FirstChanceGuard.Xunit --version 1.0.0
                    
#r "nuget: FirstChanceGuard.Xunit, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FirstChanceGuard.Xunit@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FirstChanceGuard.Xunit&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=FirstChanceGuard.Xunit&version=1.0.0
                    
Install as a Cake Tool

FirstChanceGuard.Xunit

Fail any xUnit v3 test that throws an exception on a path that was supposed to just work.

Your test suite is green. Run it under the debugger and it crawls, and nobody can say why. Somewhere in your code a method throws, catches its own exception, and keeps going. The code works and the test passes, so the throw never shows up where you would look. The debugger sees it. Every exception raises a first-chance notification the moment it happens, before any catch runs, and an attached debugger handles each one. Put that throw-and-catch in a loop that loads a few thousand rows and a green suite that should take seconds takes minutes. The same cost shows up when you debug the app itself.

Most developers have never gone looking for first-chance exceptions. FirstChanceGuard.Xunit watches for them while your tests run and fails the test that caused an unexpected one, so the hidden cost becomes a red test with a name and a line number.

Install

<PackageReference Include="FirstChanceGuard.Xunit" Version="0.1.0-*" />

Depends only on xunit.v3.extensibility.core. Needs .NET 10 and xUnit v3.

Arm the handler, then turn the guard on

Two steps. Arming attaches the handler that records throws. The attribute turns a recorded throw into a failed test. You need both, and the handler has to be armed before any test runs.

// 1. Arm before any test runs (no warm-up needed).
[assembly: Xunit.v3.TestPipelineStartup(typeof(FirstChanceGuard.Xunit.FirstChanceGuardPipelineStartup))]

// 2. Watch every test in the assembly.
[assembly: FirstChanceExceptionGuard]

Attach [FirstChanceExceptionGuard] to a class or a method instead when you want narrower coverage.

Turn it on early and there is a second payoff. Every happy-path throw fails a test, so exceptions used as control flow cannot quietly take root. You either stop throwing on the normal path or mark the throw as expected on purpose.

When you need a warm-up

Some libraries throw-and-catch on first use, during one-time static setup. bUnit's first render triggers AngleSharp's encoding probe, for instance. Arm from a [ModuleInitializer] and run the warm-up first, so that one-time noise happens before the handler goes live:

using System.Runtime.CompilerServices;
using FirstChanceGuard.Xunit;

internal static class FirstChanceGuardSetup
{
    [ModuleInitializer]
    public static void Init() => FirstChanceExceptionGuardAttribute.Arm(static () =>
    {
        using var context = new BunitContext();
        context.Render(builder => builder.AddMarkupContent(0, "<p>warm-up</p>"));
    });
}

Arm(preWarm, typeof(SomeExpectedException)) adds suite-wide exemptions. OperationCanceledException is exempt already.

Opt out the tests that throw on purpose

[Fact]
[FirstChanceExceptionsExpected]                          // may throw anything
public void Parsing_garbage_throws() { /* ... */ }

[Fact]
[FirstChanceExceptionsExpected(typeof(FormatException))] // only FormatException; anything else still fails
public void Parsing_reports_a_format_error() { /* ... */ }

Works on a method or a whole class. A method-level list wins over a class-level one, and the annotation doubles as documentation of which paths throw by design.

Measure one operation

Want to prove a single call throws nothing on its happy path, without arming the whole suite? FirstChanceExceptions.CountDuring runs your delegate and hands back the count:

FirstChanceExceptions.CountDuring(() => parser.Parse(validInput)).ShouldBe(0);

It counts every exception type and stays on the calling thread, so it is safe under parallel runs.

Docs and license

Full guide and source: https://github.com/brhinescot/FirstChanceGuard.Xunit

MIT licensed.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated