Skip to content

Fix ArgumentDisplayFormatter ignored due to premature display name caching - #3543

Merged
thomhurst merged 3 commits into
mainfrom
copilot/fix-argument-display-formatter
Oct 27, 2025
Merged

Fix ArgumentDisplayFormatter ignored due to premature display name caching#3543
thomhurst merged 3 commits into
mainfrom
copilot/fix-argument-display-formatter

Conversation

CopilotAI commented Oct 27, 2025

Copy link
Copy Markdown
Contributor

Custom ArgumentDisplayFormatter attributes were ignored because the display name was computed and cached before discovery event receivers ran, where formatters are registered.

publicclassFoo{publicoverridestringToString()=>thrownewException("Should not be called");}[Test][MethodDataSource(nameof(Data))][ArgumentDisplayFormatter<FooFormatter>]// Was being ignoredpublicvoidTest(Foofoo){}

Changes

  • TUnit.Core/TestContext.cs: Added InvalidateDisplayNameCache() to clear cached display name
  • TUnit.Engine/Building/TestBuilder.cs: Invalidate cache after discovery event receivers complete in BuildTestAsync()
  • TUnit.TestProject/ArgumentDisplayFormatterTests.cs: Added test coverage for formatters with MethodDataSource, Arguments, and exception-throwing ToString()

Flow

Before: GetDisplayName() → cache result → discovery events → formatters registered (too late)

After: GetDisplayName() → cache result → discovery events → formatters registered → invalidate cache → next GetDisplayName() uses formatters

Original prompt

This section details on the original issue you should resolve

<issue_title>ArgumentDisplayFormatter is being ignored in 0.77.3</issue_title>
<issue_description>A custom ArgumentDisplayFormatter is being ignored. Here's a minimal reproduction with a failing test because of it (here's a repo with the repro):

publicclassTests{[Test][MethodDataSource(nameof(Data1))][ArgumentDisplayFormatter<FooFormatter>]publicvoidTest1(Foofoo){}publicIEnumerable<Foo>Data1()=>[new()];}publicclassFoo{publicoverridestringToString()=>thrownewException("Foo.ToString");}publicclassFooFormatter:ArgumentDisplayFormatter{publicoverrideboolCanHandle(object?value)=>true;publicoverridestringFormatValue(object?value)=>"FooFormatterValue";}

The test fails because the FooFormatter isn't being used and the Foo.ToString() method gets called and throws:

PS D:\Projects\others\TUnitBugs> dotnet test
Restore complete (0.4s)
TUnitBugs succeeded (0.2s) → TUnitBugs\bin\Debug\net9.0\TUnitBugs.dll
TUnitBugs test failed with 2 error(s) (0.4s)
D:\\Projects\\others\\TUnitBugs\\TUnitBugs\\Tests.cs(3): error test failed: Test1 (0ms): InvalidOperationException: Failed to expand data sourcefortest'Test1': Foo.ToString
D:\Projects\others\TUnitBugs\TUnitBugs\bin\Debug\net9.0\TUnitBugs.dll : error run failed: Tests failed: 'D:\Projects\others\TUnitBugs\TUnitBugs\bin\Debug\net9.0\TestResults\TUnitBugs_net9.0_x64.log' [net9.0|x64]
Test summary: total: 1, failed: 1, succeeded: 0, skipped: 0, duration: 0.3s
Build failed with 2 error(s) in 1.1s

I found that this happens because the argument display value is computed before the formatter is added.

The argument display value is being created here:

// Create the test object BEFORE invoking event receivers
// This ensures context.InternalExecutableTest is set for error handling in registration
varcreationContext=newExecutableTestCreationContext
{
TestId=testId,
DisplayName=context.GetDisplayName(),
Arguments=testData.MethodData,
ClassArguments=testData.ClassData,
Context=context,
TestClassInstanceFactory=testData.TestClassInstanceFactory,
ResolvedMethodGenericArguments=testData.ResolvedMethodGenericArguments,
ResolvedClassGenericArguments=testData.ResolvedClassGenericArguments
};

Which happens before the events are executed for the test later:

awaitInvokeDiscoveryEventReceiversAsync(context);

And ArgumentDisplayFormatterAttribute depends on having it's OnTestDiscovered executed so it could add the argument formatter.

I discovered this, because I have a class that throws for the default argument formatter, so I'm using a custom one to make sure my tests don't fail. Except right now the tests are failing anyways.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

CopilotAIand others added 2 commits October 27, 2025 20:44
Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
…iscovery
Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
CopilotAI changed the title [WIP] Fix ArgumentDisplayFormatter handling in testsFix ArgumentDisplayFormatter ignored due to premature display name cachingOct 27, 2025
CopilotAI requested a review from thomhurstOctober 27, 2025 20:53
@thomhurst
thomhurst marked this pull request as ready for review October 27, 2025 20:55
@thomhurst
thomhurst enabled auto-merge (squash) October 27, 2025 20:55
@thomhurst
thomhurst merged commit 125bdfb into mainOct 27, 2025
19 of 21 checks passed
@thomhurst
thomhurst deleted the copilot/fix-argument-display-formatter branch October 27, 2025 21:18
@claudeclaudeBot mentioned this pull request Oct 27, 2025
1 task
Sign up for freeto 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.

ArgumentDisplayFormatter is being ignored in 0.77.3

2 participants

@thomhurst