Repository navigation
Description
What happens
A generic test class can have class data sources that cannot supply a class type argument, because no public constructor parameter uses a class type parameter. In that case a method-level [Arguments(null)] row is dropped instead of inferring object.
[Arguments(42)]
[MethodDataSource(typeof(Sources), nameof(Sources.FortyThree))] // untyped class source
public class C<T>(int number)
{
[Test]
[Arguments(null)]
public async Task Run(T value) { }
}From reading the source generator: TestMetadataGenerator.GetConcreteInstantiations computes classTypeArgumentsSupplied (the null-row rule from #7141). #7337 (#7209) excludes class [Arguments] rows whose values go to no type parameter, but every other class data source still counts as supplying the class type arguments. So [Arguments(null)] infers no type, and since no class row instantiates C<object>, the row produces no test.
Reported by CodeRabbit on #7337: #7337 (comment)
Expected
When no public constructor parameter contains a class type parameter, class data sources cannot supply the class type arguments. Method rows should then infer them as without a class data source: C<object> for [Arguments(null)], built from the class sources' rows. This should be the same in both modes.
Notes
- The core class
[Arguments]rule shipped in fix(generic): a type-free class [Arguments] row lets method rows infer T, with matching constructor binding in both modes #7392; fix(generic): class [Arguments] row that infers no type argument lets method rows infer it #7337 was closed after splitting its scope. This issue extends that rule to other class sources whose constructor parameters cannot supply the class type arguments. Generic class row that infers no type argument: reflection parity beside other data sources #7390 covers parity beside a type-free[Arguments]row, rather than this general classification rule. - Reflection mode groups the rows of non-
[Arguments]class sources by their run-time value types (ReflectionTestDataCollector.GroupClassRowsByTypeArgumentsAsync). Check whether it infersTfrom a value bound to a non-Tconstructor parameter, the reflection half of Generic class with a class [Arguments] row that infers no type argument: modes disagree on T and constructor values, source-gen drops [Arguments(null)] #7209, before changing the generator. - Not reproduced at run time yet. Reproduce both modes with a
tests/TUnit.TestProject/Bugs/<N>fixture and--treenode-filter, with and without--reflection.
Acceptance criteria
- Reproduce the example on current main in both modes before changing inference.
- Non-Arguments class sources cannot infer class type arguments from constructor parameters that contain no class type parameter.
- The null method row runs on
C<object>with each class source row supplying its constructor value, with identical counts and values in both modes.
Activity
thomhurst commentedon Nov 2, 2026
Triage: added a native blocked_by #7209. PR #7337 for #7209 changes
classTypeArgumentsSuppliedinTestMetadataGenerator.GetConcreteInstantiations, the rule this issue extends. Fixing this first would conflict with that PR.thomhurst commentedon Nov 3, 2026
Removed the closed #7209 dependency: the core rule merged in #7392 (ca4437c).
classTypeArgumentsSuppliedstill excludes only type-free[Arguments]rows, not other sources whose constructor parameters cannot infer T. #7390 covers parity beside a type-free[Arguments]row; this issue additionally needs non-Arguments class sources to be recognized as type-free. Runtime reproduction remains required.