惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
Microsoft Security Blog
Microsoft Security Blog
Google DeepMind News
Google DeepMind News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
博客园_首页
T
Tailwind CSS Blog
aimingoo的专栏
aimingoo的专栏
A
About on SuperTechFans
T
The Blog of Author Tim Ferriss
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
P
Proofpoint News Feed
博客园 - 司徒正美
有赞技术团队
有赞技术团队
Engineering at Meta
Engineering at Meta
Last Week in AI
Last Week in AI
MongoDB | Blog
MongoDB | Blog

Duende Software Official Site

The Backend for Frontend Pattern Is Now Official IETF Guidance: RFC 10017 Published WhatsApp One-Time Password (OTP) Login with Duende IdentityServer and User Management Planning a Successful Migration from IdentityServer3 to Duende IdentityServer Client Secrets, Mutual TLS and Private Key JWT, Oh My! How To Spell "Duende" Understanding .NET 11 Automatic CSRF Protection: A Guide for Identity Developers Security Lingo Explained: TOTP (Time-based One-Time Password) Custom Passkey Attestation Policies: Restricting Login to Hardware Keys OAuth Identity Chaining, Transaction Tokens, and Human-in-the-Loop: Summer 2026 Identity Standards Recap What is Identity? - The Question Every Team Should Answer Before Writing Code Security Is a Spectrum: How to Choose Session Lifetimes in Duende IdentityServer Passkeys and WebAuthn with Duende IdentityServer and User Management Authenticating Players in Godot 4 with OAuth 2.0 and OpenID Connect Hardening OAuth in the newest 2026-07-28 MCP Release Candidate Unify Your SAML and OIDC Signing Keys with Automatic Rotation and Duende IdentityServer Duende Software Duende Software Duende Software Duende Software Duende Software Duende Software Duende Software Stop AI Bots from Wasting Your Server How Duende IdentityServer Filters Claims (And Why It Matters) Core vs Extended Protocols in Duende IdentityServer v8: What You Get and When You Need More Your IdentityServer v8 Upgrade Checklist: A Quick Pre-Flight Guide Setting Up SAML Single Sign-On in ASP.NET with Duende IdentityServer Your Identity, Your Terms: Duende's Modular Identity Infrastructure and v8.x Release Duende Spring Launch '26: Identity Infrastructure That Expands With You SAML and OpenID Connect (OIDC): Coexistence, Not Competition
Duende Software
Khalid Abuhakmeh, Maarten Balliauw · 2026-07-09 · via Duende Software Official Site

Every test you write needs a place to run. Before the assertions fire, before the snapshots compare, before a single line of application code gets exercised, something has to discover your tests, spin up the runtime, manage parallelism, and report results. For most .NET developers, that something is xUnit.net, and it’s so good at its job that you probably never think about it.

That invisible reliability is exactly why we’re sponsoring it. Let’s hear from the current maintainer as to what motivated them to build such a foundational project:

"I have been a developer using Test Driven Development for more than 20 years, and xUnit.net represents the codified guidance that Jim Newkirk and I would frequently give at development conferences to teach others how to get the most out of unit testing. Now that I’m retired, sponsorships like this help keep xUnit.net moving forward."
– Brad Wilson

Join us in congratulating our sixth open-source sponsorship, xUnit.net.

What is xUnit.net?

xUnit.net is a free, open-source, community-focused unit testing tool for .NET. Created by Brad Wilson and James Newkirk (the original author of NUnit), xUnit.net was built from the ground up to incorporate the lessons learned from earlier testing frameworks. The result is a lean, extensible, opinionated framework that trusts developers to write tests the way they want.

Developers commonly refer to the project as “xUnit,” though the official name is xUnit.net. Either is perfectly acceptable in conversation.

xUnit.net v3 is the current major release, supporting .NET 8.0 or later and .NET Framework 4.7.2 or later. It runs everywhere you’d expect: the .NET SDK command line, Visual Studio, Visual Studio Code, JetBrains Rider, and NCrunch. The project is part of the .NET Foundation, licensed under Apache 2.0, and has earned over 4,500 stars on GitHub with 27,400+ projects depending on it. Brad Wilson alone has made over 2,600 contributions to the repository.

The framework’s philosophy rests on a few core principles: simplicity (tests are just classes with methods), extensibility (almost everything can be overridden or replaced), and sensible defaults (parallelism is on by default, test class isolation is the norm). These design decisions make xUnit.net feel less like a framework you fight and more like one that stays out of your way.

What sets xUnit.net apart from earlier frameworks is how it handles the test lifecycle. There’s no [SetUp] or [TearDown]. Instead, constructors and IDisposable handle per-test setup and cleanup. Shared state across tests uses IClassFixture<T> or ICollectionFixture<T>, making resource lifetimes explicit rather than hidden behind attribute conventions. This approach makes tests easier to reason about and reduces the surprises that come from shared mutable state between test methods.

Getting Started

To add xUnit.net to an existing test project, install the NuGet package:

Shell

dotnet add package xunit.v3

That’s it. No runner packages to install separately, no additional configuration files. xUnit.net v3 includes a built-in runner, so you execute your tests with dotnet run rather than dotnet test (though dotnet test still works via the Visual Studio adapter).

Here’s a simple test class showing both [Fact] (a single test case) and [Theory] (a parameterized test):

Csharp

namespace MyProject.Tests;

public class CalculatorTests
{
    [Fact]
    public void Adding_two_and_two_returns_four()
    {
        var result = 2 + 2;
        Assert.Equal(4, result);
    }

    [Theory]
    [InlineData(1, 1, 2)]
    [InlineData(5, 3, 8)]
    [InlineData(0, 0, 0)]
    public void Addition_is_correct(int a, int b, int expected)
    {
        var result = a + b;
        Assert.Equal(expected, result);
    }
}

Run the tests:

xUnit.net v3 In-Process Runner v3.2.2 (64-bit .NET 10.0.8)
  Discovering: MyProject.Tests
  Discovered:  MyProject.Tests
  Starting:    MyProject.Tests
  Finished:    MyProject.Tests
=== TEST EXECUTION SUMMARY ===
   MyProject.Tests  Total: 4, Errors: 0, Failed: 0, Skipped: 0, Not Run: 0, Time: 0.032s

xUnit.net at Duende

xUnit.net runs under every test we write at Duende Software. Every Shouldly assertion and every Verify snapshot across our products executes on xUnit.net. It powers our IdentityServer tests, our BFF Security Framework integration tests, our open-source library tests, and our end-to-end Playwright tests. When we say we care about testing, xUnit.net is where that commitment lives in code.

Here’s an example of how we use xUnit.net’s IClassFixture<> with WebApplicationFactory to integration test IdentityServer endpoints. This pattern works just as well for anyone testing their own IdentityServer deployment.

First, a minimal IdentityServer host:

Csharp

// Program.cs
using Duende.IdentityServer.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddIdentityServer()
    .AddInMemoryApiScopes([
        new ApiScope("api1", "My API")
    ])
    .AddInMemoryClients([
        new Client
        {
            ClientId = "client",
            AllowedGrantTypes = GrantTypes.ClientCredentials,
            ClientSecrets = { new Secret("secret".Sha256()) },
            AllowedScopes = { "api1" }
        }
    ]);

var app = builder.Build();

app.UseIdentityServer();

app.Run();

public partial class Program;

Then, integration tests that verify the discovery document:

Csharp

using System.Net;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.Testing;

namespace IdentityServerHost.Tests;

public class DiscoveryEndpointTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _client;

    public DiscoveryEndpointTests(WebApplicationFactory<Program> factory)
    {
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task Discovery_endpoint_returns_success()
    {
        var response = await _client.GetAsync("/.well-known/openid-configuration");
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    }

    [Fact]
    public async Task Discovery_endpoint_contains_expected_issuer()
    {
        var response = await _client.GetAsync("/.well-known/openid-configuration");
        var content = await response.Content.ReadAsStringAsync();
        var document = JsonDocument.Parse(content);

        Assert.True(document.RootElement.TryGetProperty("issuer", out var issuer));
        Assert.NotNull(issuer.GetString());
    }

    [Fact]
    public async Task Discovery_endpoint_lists_supported_scopes()
    {
        var response = await _client.GetAsync("/.well-known/openid-configuration");
        var content = await response.Content.ReadAsStringAsync();
        var document = JsonDocument.Parse(content);

        Assert.True(document.RootElement.TryGetProperty("scopes_supported", out var scopes));
        var scopeList = scopes.EnumerateArray()
            .Select(s => s.GetString())
            .ToList();
        Assert.Contains("api1", scopeList);
    }

    [Fact]
    public async Task Discovery_endpoint_lists_supported_grant_types()
    {
        var response = await _client.GetAsync("/.well-known/openid-configuration");
        var content = await response.Content.ReadAsStringAsync();
        var document = JsonDocument.Parse(content);

        Assert.True(
            document.RootElement.TryGetProperty("grant_types_supported", out var grantTypes));
        var grantTypeList = grantTypes.EnumerateArray()
            .Select(g => g.GetString())
            .ToList();
        Assert.Contains("client_credentials", grantTypeList);
    }
}

This test class uses IClassFixture<WebApplicationFactory<Program>> to share a single test server across all four tests. xUnit.net manages the fixture’s lifecycle: it creates the factory once before the first test runs and disposes it after the last test finishes. The tests themselves verify that the IdentityServer discovery document is accessible, contains a valid issuer, advertises the api1 scope, and supports the client_credentials grant type.

You can adapt this pattern to test any aspect of your IdentityServer configuration: token endpoint responses, introspection behavior, CORS headers, or custom endpoints.

The test project only needs two package references:

Shell

dotnet add package xunit.v3
dotnet add package Microsoft.AspNetCore.Mvc.Testing

And a project reference to your IdentityServer host. That’s all you need to start testing your identity infrastructure.

Sponsorship Details

Duende Software is sponsoring xUnit.net for the next 12 months at $250 per month (totaling $3,000 for the year).

If you benefit from xUnit.net, consider sponsoring xUnit.net on GitHub or contributing code, docs, or bug reports.

We’d like to thank Brad Wilson for his work on xUnit.net and its role in shaping how an entire generation of .NET developers write tests. This award is our third sponsorship in the testing space, following Shouldly and Verify, and it’s no coincidence. Testing is foundational to how we build secure identity software at Duende Software, and xUnit.net is the foundation under all of it.

Try It Out

If you haven’t tried xUnit.net v3 yet, now’s a good time. Check out the getting started guide and the official documentation to dive in.