Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions TUnit.Engine/Discovery/ReflectionTestDataCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,10 +357,13 @@ private static async Task<List<TestMetadata>> DiscoverTestsInAssembly(Assembly a
return discoveredTests;
}

var filteredTypes = types.Where(static t => t.IsClass && !IsCompilerGenerated(t));

foreach (var type in filteredTypes)
foreach (var type in types)
{
if (!type.IsClass || IsCompilerGenerated(type))
{
continue;
}

if (type.IsAbstract)
{
continue;
Expand Down Expand Up @@ -497,12 +500,15 @@ private static async IAsyncEnumerable<TestMetadata> DiscoverTestsInAssemblyStrea
yield break;
}

var filteredTypes = types.Where(static t => t.IsClass && !IsCompilerGenerated(t));

foreach (var type in filteredTypes)
foreach (var type in types)
{
cancellationToken.ThrowIfCancellationRequested();

if (!type.IsClass || IsCompilerGenerated(type))
{
continue;
}

// Skip abstract types - they can't be instantiated
if (type.IsAbstract)
{
Expand All @@ -528,15 +534,13 @@ private static async IAsyncEnumerable<TestMetadata> DiscoverTestsInAssemblyStrea
if (inheritsTests)
{
// Get all test methods including inherited ones
testMethods = GetAllTestMethods(type)
.Where(static m => m.IsDefined(typeof(TestAttribute), inherit: false) && !m.IsAbstract);
testMethods = GetAllTestMethods(type);
}
else
{
// Only get declared test methods
testMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static |
BindingFlags.DeclaredOnly)
.Where(static m => m.IsDefined(typeof(TestAttribute), inherit: false) && !m.IsAbstract);
BindingFlags.DeclaredOnly);
}
}
catch (Exception)
Expand All @@ -548,6 +552,11 @@ private static async IAsyncEnumerable<TestMetadata> DiscoverTestsInAssemblyStrea
{
cancellationToken.ThrowIfCancellationRequested();

if (!method.IsDefined(typeof(TestAttribute), inherit: false) || method.IsAbstract)
{
continue;
}

// Prevent duplicate test metadata for inherited tests
if (method.DeclaringType != type && !type.IsDefined(typeof(InheritsTestsAttribute), inherit: false))
{
Expand Down Expand Up @@ -1478,6 +1487,7 @@ public override Func<ExecutableTestCreationContext, TestMetadata, AbstractExecut
private static Func<object?[], object> CreateReflectionInstanceFactory(ConstructorInfo ctor)
{
var isPrepared = false;
var parameters = ctor.GetParameters();

return args =>
{
Expand All @@ -1491,7 +1501,6 @@ public override Func<ExecutableTestCreationContext, TestMetadata, AbstractExecut
}

// Cast arguments to the expected parameter types
var parameters = ctor.GetParameters();
var castedArgs = new object?[parameters.Length];

for (var i = 0; i < parameters.Length && i < args.Length; i++)
Expand Down Expand Up @@ -1676,6 +1685,10 @@ private static bool IsCovariantCompatible(Type paramType, [DynamicallyAccessedMe
private static Func<object, object?[], Task> CreateReflectionTestInvoker(Type testClass, MethodInfo testMethod)
{
var isPrepared = false;
// For non-generic methods, parameter shape is stable across invocations — hoist the
// GetParameters() call out of the hot lambda. Generic method definitions are resolved
// to a concrete MethodInfo per invocation, so they must still call GetParameters() inline.
var staticParameters = testMethod.IsGenericMethodDefinition ? null : testMethod.GetParameters();

return (instance, args) =>
{
Expand Down Expand Up @@ -1744,7 +1757,7 @@ private static bool IsCovariantCompatible(Type paramType, [DynamicallyAccessedMe
}

// Cast arguments to the expected parameter types
var parameters = methodToInvoke.GetParameters();
var parameters = staticParameters ?? methodToInvoke.GetParameters();
var castedArgs = new object?[parameters.Length];

// Check if the last parameter is a params array
Expand Down
Loading