feat: add TestContext.Isolation interface for test resource isolation#4801
feat: add TestContext.Isolation interface for test resource isolation#4801
Conversation
Extract isolation helpers (UniqueId, GetIsolatedName, GetIsolatedPrefix) from WebApplicationTest into a new ITestIsolation interface on TestContext, making them available to all tests without requiring a specific base class. WebApplicationTest now shares the same atomic counter as TestContext to ensure unique IDs across all test types. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| /// that need to be unique across parallel test execution. | ||
| /// Accessed via <see cref="TestContext.Isolation"/>. | ||
| /// </summary> | ||
| public interface ITestIsolation |
There was a problem hiding this comment.
Missing Snapshot Test Updates
This PR introduces public API changes that require updating snapshot tests per CLAUDE.md Rule 2:
Snapshot Testing - Changes to source generator output or public APIs require running snapshot tests. Commit
.verified.txtfiles. NEVER commit.received.txt.
Public API Changes Made
- New public interface:
ITestIsolation(this file) - Modified TestContext: Now implements
ITestIsolationand exposespublic ITestIsolation Isolation => this;
Required Action
Run the public API snapshot tests and commit the updated .verified.txt files:
dotnet test TUnit.PublicAPI
# Review the changes in *.verified.txt files
git add TUnit.PublicAPI/**/*.verified.txtSee mandatory-rules.md for details on when snapshot tests are required.
Add ITestIsolation interface and TestContext.Isolation property to all TFM snapshot files (net8.0, net9.0, net10.0, net4.7). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Code ReviewI found an architectural issue with the dual-counter implementation that causes inconsistent behavior for users. Issue: Inconsistent UniqueId ValuesProblem: For tests inheriting from Root Cause: Both constructors independently increment the shared counter at different lifecycle stages:
Impact: This causes // In a test inheriting from WebApplicationTest:
this.GetIsolatedName("users"); // Returns "Test_5_users"
TestContext.Current!.Isolation.GetIsolatedName("users"); // Returns "Test_1_users"This defeats the purpose of test isolation — a user mixing both APIs in the same test will get non-matching resource names. Suggested Fix: Reuse TestContext's IDInstead of generating a separate ID, have internal WebApplicationTest()
{
UniqueId = TestContext.Current!.Isolation.UniqueId;
}Why this is better:
This ensures that whether a user calls Additional Consideration: Make Helper Methods WrappersFor maximum clarity and maintainability, consider having protected string GetIsolatedName(string baseName)
=> TestContext.Current!.Isolation.GetIsolatedName(baseName);
protected string GetIsolatedPrefix(string separator = "_")
=> TestContext.Current!.Isolation.GetIsolatedPrefix(separator);This makes CLAUDE.md Compliance: ✅ No violations found. Checked snapshot tests, AOT compatibility, performance, and dual-mode requirements. |
Address code review feedback: WebApplicationTest now delegates UniqueId, GetIsolatedName, and GetIsolatedPrefix to TestContext.Current!.Isolation instead of independently incrementing the shared counter. This ensures consistent values regardless of the access path. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
ITestIsolationinterface onTestContextwithUniqueId,GetIsolatedName(), andGetIsolatedPrefix()helpersWebApplicationTestso any test can create unique resource names (database tables, queue topics, cache keys) without requiring a specific base classWebApplicationTestnow shares the same atomic counter, ensuring unique IDs across all test typesChanges
TUnit.Core/Interfaces/ITestIsolation.csTUnit.Core/TestContext.Isolation.csTUnit.Core/TestContext.csTUnit.AspNetCore/WebApplicationTest.csTUnit.UnitTests/TestIsolationTests.csdocs/docs/test-lifecycle/test-context.mddocs/docs/examples/aspnet.mdUsage
Test plan
dotnet buildsucceeds (TUnit.Core + TUnit.AspNetCore)TestIsolationTests)🤖 Generated with Claude Code