Skip to content

tests: migrate integration tests to TUnit.AspNetCore WebApplicationTest#1100

Merged
BenjaminMichaelis merged 18 commits into
mainfrom
agents/tunit-aspnetcore-integration-tests
May 17, 2026
Merged

tests: migrate integration tests to TUnit.AspNetCore WebApplicationTest#1100
BenjaminMichaelis merged 18 commits into
mainfrom
agents/tunit-aspnetcore-integration-tests

Conversation

@BenjaminMichaelis
Copy link
Copy Markdown
Member

@BenjaminMichaelis BenjaminMichaelis commented May 13, 2026

Summary

Migrates EssentialCSharp.Web.Tests to TUnit.AspNetCore using WebApplicationTest<WebApplicationFactory, Program> and TestWebApplicationFactory<Program>.

What changed

  • Added TUnit.AspNetCore package.
  • Introduced IntegrationTestBase with shared InServiceScope helpers.
  • Migrated integration-style test classes off [ClassDataSource] / constructor factory injection to IntegrationTestBase inheritance.
  • Consolidated MCP rate-limiting tests into one class while keeping per-test host isolation.
  • McpTestHelper now accepts TracedWebApplicationFactory<Program> and creates clients with explicit AllowAutoRedirect = false where redirect assertions require it.

Current implementation details

  • WebApplicationFactory stores a per-instance GUID-based SQLite connection string. A _keepAliveConnection is held open for the factory lifetime to keep the shared-cache in-memory database alive. DbConnection is registered as scoped so each request scope gets its own SqliteConnection, avoiding concurrent-access locking from sharing a single connection instance.
  • Test schema creation runs through EnsureCreatedHostedService, registered at index 0 in the service collection so hosted-service startup runs schema creation first.
  • Schema creation is serialized per factory instance to prevent concurrent EnsureCreatedAsync() races in CI.
  • Functional tests use GetFollowingGetRedirectsAsync (GET-only redirect helper) and non-auto-redirect clients where status/location assertions depend on raw redirect responses.

Notes

  • This PR no longer uses ConcurrentBag<SqliteConnection>, Interlocked disposal guards, or CreateRedirectFollowingClient().
  • Build compiles cleanly after these updates.

- Add TUnit.AspNetCore 1.40.5 package reference
- Create IntegrationTestBase : WebApplicationTest<WebApplicationFactory, Program>
  for per-test factory isolation, InServiceScope helpers, and trace correlation
- Rewrite WebApplicationFactory to extend TestWebApplicationFactory<Program>
  (removes IAsyncInitializer, moves to ConcurrentBag for multi-connection tracking)
- Migrate all test classes to inherit from IntegrationTestBase:
  - Remove [NotInParallel] and [ClassDataSource<WebApplicationFactory>] attributes
  - Collapse 6 McpRateLimitingTests classes into 1 (fresh DI per test = fresh rate limiter)
  - Update McpTestHelper to accept TracedWebApplicationFactory<Program>
  - Use Factory.Inner.CreateClient(options) where AllowAutoRedirect=false is needed
- Remove TUnit.Core.Interfaces import (IAsyncInitializer no longer used)
… following

TracedWebApplicationFactory.CreateClient() uses CreateDefaultClient() which
sets AllowAutoRedirect=false. Tests expecting 200/404 after app-level redirects
(e.g. / -> first chapter) need Factory.Inner.CreateClient() which defaults to
AllowAutoRedirect=true.
…pe helpers

- McpTestHelper.CreateClient: factory.Inner.CreateClient(options) -> factory.CreateClient()
  TracedWebApplicationFactory.CreateClient() already uses AllowAutoRedirect=false;
  going through Inner was silently bypassing activity propagation for all MCP tests.

- ContentRateLimitingTests: same fix - Factory.Inner -> Factory.CreateClient()

- FunctionalTests: introduce CreateRedirectFollowingClient() helper on IntegrationTestBase
  to document the explicit AllowAutoRedirect=true trade-off; all three test methods use it
  since the app issues redirects even for 404 responses.

- IntegrationTestBase: add InServiceScopeAsync<T> and InServiceScopeAsync overloads
  so callers no longer need to manually manage IServiceScope for async DB/service work.

- WebApplicationFactory: add Interlocked disposal guard to prevent double-dispose
  of SqliteConnection instances when both DisposeAsync and Dispose(bool) are called.
Copilot AI review requested due to automatic review settings May 13, 2026 16:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the integration test project from a hand-rolled WebApplicationFactory<Program> + IAsyncInitializer setup to TUnit.AspNetCore's first-class WebApplicationTest<TFactory, TEntryPoint> pattern, giving per-test factory isolation, trace correlation, and removing the need for [NotInParallel] and [ClassDataSource] attributes.

Changes:

  • Adds TUnit.AspNetCore 1.40.5; subclasses TestWebApplicationFactory<Program> and tracks SQLite connections in a ConcurrentBag with Interlocked disposal guard.
  • Introduces IntegrationTestBase providing InServiceScope[Async] helpers and a CreateRedirectFollowingClient() escape hatch for redirect-following clients.
  • Refactors all integration test classes to inherit IntegrationTestBase; merges six MCP rate-limiting classes into one (each method now gets a fresh factory/limiter).

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Directory.Packages.props Add TUnit.AspNetCore 1.40.5 package version.
EssentialCSharp.Web.Tests/EssentialCSharp.Web.Tests.csproj Reference new TUnit.AspNetCore package.
EssentialCSharp.Web.Tests/WebApplicationFactory.cs Switch base type, track connections in ConcurrentBag, add disposal guard.
EssentialCSharp.Web.Tests/IntegrationTestBase.cs New base class with service-scope helpers and redirect-following client helper.
EssentialCSharp.Web.Tests/McpTestHelper.cs Accept TracedWebApplicationFactory<Program>; drop AllowAutoRedirect=false.
EssentialCSharp.Web.Tests/McpRateLimitingTests.cs Collapse six classes into one with six tests; remove [NotInParallel].
EssentialCSharp.Web.Tests/McpTests.cs Use new base; replace factory with Factory.
EssentialCSharp.Web.Tests/McpToolContractTests.cs Use new base; replace factory with Factory.
EssentialCSharp.Web.Tests/McpApiTokenServiceTests.cs Use new base; replace factory with Factory.
EssentialCSharp.Web.Tests/ContentRateLimitingTests.cs Use new base; inline AllowAutoRedirect=false no longer needed (default).
EssentialCSharp.Web.Tests/FunctionalTests.cs Use new base and CreateRedirectFollowingClient() to preserve redirect-following behavior.
EssentialCSharp.Web.Tests/ListingSourceCodeControllerTests.cs Use new base; replace factory with Factory.
EssentialCSharp.Web.Tests/RouteConfigurationServiceTests.cs Use new base; call InServiceScope on the base.
EssentialCSharp.Web.Tests/SitemapXmlHelpersTests.cs Use new base; replace _Factory with Factory.

Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs
The shared _disposed flag was blocking base.Dispose(bool) when DisposeAsync
ran first — the base's async path may call Dispose(true), which our guard
intercepted, skipping base resource cleanup.

Fix: use a _connectionsDisposed flag that only gates the SQLite connection
cleanup (which we own). Base disposal calls are always forwarded. Also
removes the redundant GC.SuppressFinalize — the base class handles it.

Addresses Copilot PR review comments.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Fixed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

EssentialCSharp.Web.Tests/WebApplicationFactory.cs:69

  • If EnsureCreated() (or any other call between line 52 and 75) throws, the SqliteConnection created on line 52 is not disposed — the local variable goes out of scope while the connection is still open. Consider wrapping the connection in a using (or try/catch) and only handing ownership over after schema creation succeeds, or hooking it up to the factory's disposal so failures during configuration don't leak the connection and in-memory database.
            SqliteConnection connection = new(SqlConnectionString);
            connection.Open();

            services.AddSingleton<DbConnection>(connection);

            services.AddDbContext<EssentialCSharpWebContext>((serviceProvider, options) =>
            {
                DbConnection dbConnection = serviceProvider.GetRequiredService<DbConnection>();
                options.UseSqlite(dbConnection);
            });

            DbContextOptions<EssentialCSharpWebContext> dbContextOptions =
                new DbContextOptionsBuilder<EssentialCSharpWebContext>()
                    .UseSqlite(connection)
                    .Options;
            using EssentialCSharpWebContext db = new(dbContextOptions);

            db.Database.EnsureCreated();

Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
Comment thread EssentialCSharp.Web.Tests/SitemapXmlHelpersTests.cs
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Comment thread EssentialCSharp.Web.Tests/McpTestHelper.cs Outdated
Comment thread EssentialCSharp.Web.Tests/ContentRateLimitingTests.cs Outdated
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
… DbConnection

- Rename CreateClientWithoutRedirectFollowing -> CreateClientWithoutAutoRedirect
  (clearer name, avoids double-negative)
- Fix XML doc comment on the helper (was copy-pasted from GetFollowingGetRedirectsAsync)
- Change DbConnection from singleton to scoped with a keep-alive connection,
  preventing SQLite 'database is locked' errors under concurrent requests
- Add Dispose(bool) override to clean up _keepAliveConnection
- Update PR description: correct method name and hosted-service ordering description
Remove prior matching registrations for DbContext options, DbConnection, DatabaseMigrationService, and EnsureCreatedHostedService before re-adding test overrides. Also keep the SQLite keep-alive connection creation guarded with ??= across repeated ConfigureServices invocations.

This avoids duplicate EnsureCreated hosted services racing each other and failing CI with SQLite Error 1: table AspNetRoles already exists.
Copilot AI review requested due to automatic review settings May 17, 2026 03:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (3)

EssentialCSharp.Web.Tests/WebApplicationFactory.cs:126

  • The keep-alive connection is disposed before base.Dispose(disposing) is called. base.Dispose is what tears down the test host and its DI container, which may still hold scoped SqliteConnection instances and/or trigger graceful shutdown logic that touches the database (e.g. hosted services' StopAsync, EF interceptors). Once the keep-alive connection is closed first, the shared-cache in-memory database can be dropped while host shutdown is still running, which can produce spurious "no such table" or "database is locked" errors during disposal. Consider calling base.Dispose(disposing) first and disposing _keepAliveConnection afterwards.
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _keepAliveConnection?.Dispose();
        }
        base.Dispose(disposing);
    }

EssentialCSharp.Web.Tests/WebApplicationFactory.cs:136

  • EnsureCreatedHostedService creates a service scope synchronously with using IServiceScope scope = ... but the scope resolves a scoped DbConnection (an async-disposable SqliteConnection) and an EF DbContext. Synchronous disposal of a scope containing async-disposable resources can run their fallback synchronous Dispose path, which is not ideal for SQLite connections opened against an in-memory shared cache. Prefer await using IServiceScope scope = ... (or AsyncServiceScope) so the scope is disposed asynchronously, consistent with the async StartAsync method.
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            using IServiceScope scope = serviceProvider.CreateScope();
            EssentialCSharpWebContext dbContext =
                scope.ServiceProvider.GetRequiredService<EssentialCSharpWebContext>();
            await dbContext.Database.EnsureCreatedAsync(cancellationToken);
        }

EssentialCSharp.Web.Tests/WebApplicationFactory.cs:110

  • EnsureCreatedHostedService is inserted before the first descriptor whose ServiceType == typeof(IHostedService) to "guarantee it runs first". This relies on GenericWebHostService (the descriptor that actually starts the Kestrel/test server) being the first registered hosted service. If any other hosted service was registered earlier in Program.cs (or gets added later via a library), EnsureCreatedHostedService will instead run just before that service but still after any preceding hosted services, which would then start without a schema. A more robust approach is to clear/preserve all IHostedService descriptors and re-insert with EnsureCreatedHostedService explicitly first, or to seed the schema synchronously inside ConfigureWebHost (as the previous code did) before the host starts.
            ServiceDescriptor ensureCreatedDescriptor =
                ServiceDescriptor.Singleton<IHostedService, EnsureCreatedHostedService>();
            int firstHostedServiceIndex = -1;
            for (int i = 0; i < services.Count; i++)
            {
                if (services[i].ServiceType == typeof(IHostedService))
                {
                    firstHostedServiceIndex = i;
                    break;
                }
            }
            if (firstHostedServiceIndex >= 0)
            {
                services.Insert(firstHostedServiceIndex, ensureCreatedDescriptor);
            }
            else
            {
                services.Add(ensureCreatedDescriptor);
            }

Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/FunctionalTests.cs Outdated
Comment thread EssentialCSharp.Web.Tests/McpApiTokenServiceTests.cs
…in functional tests

Add a static SemaphoreSlim gate around EnsureCreatedHostedService.StartAsync so parallel host startup cannot race while creating schema in shared in-memory SQLite. Also use CreateClientWithoutAutoRedirect in FunctionalTests so redirect handling stays explicit in GetFollowingGetRedirectsAsync.
… explicit

Use explicit single-or-none descriptor removal (throws if duplicates are present) for DbContext options, DbConnection, DatabaseMigrationService, and EnsureCreatedHostedService. Keep schema creation serialized via semaphore. Update FunctionalTests to use CreateClientWithoutAutoRedirect so manual redirect handling remains intentional.
Copilot AI review requested due to automatic review settings May 17, 2026 04:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 8 comments.

Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/McpTestHelper.cs
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
…tracts

- Use traced client creation paths in IntegrationTestBase and McpTestHelper
- Make InServiceScope helper methods protected
- Clarify GET-only redirect helper intent
- Remove unnecessary explicit System.Threading using
- Use pooled SQLite connection string and clarify scoped DbConnection ownership
- Insert EnsureCreatedHostedService at index 0 for deterministic startup ordering
- Remove global schema semaphore after hardening descriptor replacement checks
Use a per-factory SemaphoreSlim for EnsureCreatedHostedService so concurrent host startup for the same WebApplicationFactory cannot race while creating the in-memory SQLite schema. Remove Pooling=True from the in-memory SQLite connection string to keep database lifetime governed by the explicit keep-alive connection.
Copilot AI review requested due to automatic review settings May 17, 2026 04:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

EssentialCSharp.Web.Tests/WebApplicationFactory.cs:88

  • EnsureCreatedHostedService is registered as Singleton<IHostedService> capturing the root IServiceProvider. Inserting it at index 0 only guarantees it runs first among services already in the collection at the time of Insert(0, …); any IHostedService registered later in the pipeline (e.g. by framework code or other ConfigureServices calls run after this one) will still execute before it isn’t affected, but more importantly the framework's existing schema-dependent hosted services (which this is intended to precede) may already be earlier in the list or get re-ordered. Consider sorting/asserting position by re-checking before host build, or using a more deterministic mechanism (e.g. an IHostStartupFilter or running EnsureCreated explicitly before Server is materialized).
            ServiceDescriptor ensureCreatedDescriptor =
                ServiceDescriptor.Singleton<IHostedService>(
                    serviceProvider => new EnsureCreatedHostedService(
                        serviceProvider,
                        _schemaInitializationGate));
            services.Insert(0, ensureCreatedDescriptor);

EssentialCSharp.Web.Tests/WebApplicationFactory.cs:104

  • _schemaInitializationGate is a SemaphoreSlim that is never disposed. Although schema initialization runs only once per factory, the semaphore is held for the factory's lifetime and Dispose(bool disposing) only disposes _keepAliveConnection. Add _schemaInitializationGate.Dispose() in the disposing branch.
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _keepAliveConnection?.Dispose();
        }
        base.Dispose(disposing);
    }

Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs Outdated
Comment thread EssentialCSharp.Web.Tests/McpTestHelper.cs Outdated
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
- Restore AllowAutoRedirect=false clients via Factory.Inner.CreateClient(...) in IntegrationTestBase and McpTestHelper
- Initialize keep-alive SQLite connection in WebApplicationFactory constructor
- Keep per-factory schema initialization gate to prevent EnsureCreated races in CI
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Comment on lines +133 to 151
private sealed class EnsureCreatedHostedService(
IServiceProvider serviceProvider,
SemaphoreSlim schemaInitializationGate) : IHostedService
{
base.Dispose(disposing);
if (disposing)
public async Task StartAsync(CancellationToken cancellationToken)
{
_Connection?.Dispose();
_Connection = null;
await schemaInitializationGate.WaitAsync(cancellationToken);
try
{
using IServiceScope scope = serviceProvider.CreateScope();
EssentialCSharpWebContext dbContext =
scope.ServiceProvider.GetRequiredService<EssentialCSharpWebContext>();
await dbContext.Database.EnsureCreatedAsync(cancellationToken);
}
finally
{
schemaInitializationGate.Release();
}
}
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs Outdated
Comment thread EssentialCSharp.Web.Tests/IntegrationTestBase.cs
Comment thread EssentialCSharp.Web.Tests/WebApplicationFactory.cs
Dispose the last HttpResponseMessage in GetFollowingGetRedirectsAsync before throwing when max redirects is exceeded.
…open

Clarify that EnsureCreatedHostedService is prepended via Insert(0), and guard per-scope SqliteConnection.Open() with dispose-on-failure semantics.
Copilot AI review requested due to automatic review settings May 17, 2026 07:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Comment on lines +106 to +111
if (disposing)
{
_keepAliveConnection.Dispose();
_schemaInitializationGate.Dispose();
}
base.Dispose(disposing);
private readonly string _sqlConnectionString =
$"DataSource=file:{Guid.NewGuid():N}?mode=memory&cache=shared";

private readonly SemaphoreSlim _schemaInitializationGate = new(1, 1);
Comment on lines +18 to +19
public static HttpClient CreateClient(TracedWebApplicationFactory<Program> factory) =>
factory.Inner.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false });
Comment on lines +22 to +52
protected static async Task<HttpResponseMessage> GetFollowingGetRedirectsAsync(
HttpClient client,
string relativeUrl,
int maxRedirects = 10)
{
HttpResponseMessage response = await client.GetAsync(relativeUrl);

for (int redirectCount = 0;
redirectCount < maxRedirects && IsRedirectStatusCode(response.StatusCode);
redirectCount++)
{
Uri? location = response.Headers.Location;
if (location is null)
{
return response;
}

response.Dispose();

response = await client.GetAsync(location);
}

if (IsRedirectStatusCode(response.StatusCode))
{
response.Dispose();
throw new InvalidOperationException(
$"Exceeded redirect limit ({maxRedirects}) for '{relativeUrl}'. Last status: {(int)response.StatusCode} {response.StatusCode}.");
}

return response;
}
Comment on lines +46 to +48
response.Dispose();
throw new InvalidOperationException(
$"Exceeded redirect limit ({maxRedirects}) for '{relativeUrl}'. Last status: {(int)response.StatusCode} {response.StatusCode}.");
Comment on lines +10 to 12
/// Each test method gets its own per-test factory (fresh IHost + rate limiter state)
/// via TUnit.AspNetCore's WebApplicationTest, so [NotInParallel] is no longer needed.
/// </summary>
@BenjaminMichaelis BenjaminMichaelis merged commit 80585d8 into main May 17, 2026
12 checks passed
@BenjaminMichaelis BenjaminMichaelis deleted the agents/tunit-aspnetcore-integration-tests branch May 17, 2026 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants