Skip to content

ArgumentDisplayFormatter is being ignored in 0.77.3 #3542

@Brokolis

Description

@Brokolis

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):

public class Tests
{
    [Test]
    [MethodDataSource(nameof(Data1))]
    [ArgumentDisplayFormatter<FooFormatter>]
    public void Test1(Foo foo)
    {
    }

    public IEnumerable<Foo> Data1() => [new()];
}

public class Foo
{
    public override string ToString() => throw new Exception("Foo.ToString");
}

public class FooFormatter : ArgumentDisplayFormatter
{
    public override bool CanHandle(object? value) => true;

    public override string FormatValue(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 source for test '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
var creationContext = new ExecutableTestCreationContext
{
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:

await InvokeDiscoveryEventReceiversAsync(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.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions