-
-
Notifications
You must be signed in to change notification settings - Fork 108
perf: filter-aware test collection for faster filtered runs #4296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
SummaryThis PR implements filter-aware test collection to significantly improve performance for filtered test runs by pre-filtering test sources by type before metadata materialization. Critical Issues1. Method Overload Ambiguity in TestBuilderPipeline.cs The new Existing method (line 121): public async Task<IEnumerable<AbstractExecutableTest>> BuildTestsFromMetadataAsync(
IEnumerable<TestMetadata> testMetadata,
TestBuildingContext buildingContext)New method added: public async Task<IEnumerable<AbstractExecutableTest>> BuildTestsFromMetadataAsync(
IEnumerable<TestMetadata> metadata,
TestBuildingContext buildingContext,
CancellationToken cancellationToken = default)When called with just 2 parameters, the compiler cannot determine which overload to use. This will cause compilation errors at call sites. Fix: Either:
The existing method is called at:
SuggestionsNone - the optimization approach is sound and follows TUnit's performance-first principles. Verdict |
Implements pre-filtering of test sources by type before metadata materialization, significantly improving performance for filtered test runs (e.g., --treenode-filter). Key changes: - Add FilterHints struct to extract assembly, namespace, class, and method name hints from TreeNodeFilter - Add CouldTypeMatch method to quickly filter types without full metadata processing - Add filter-aware CollectTestsAsync overload to ITestDataCollector - Update AotTestDataCollector to pre-filter Sources.TestSources by type - Add BuildTestsFromMetadataAsync to avoid redundant metadata collection - Update TestDiscoveryService to pass pre-collected metadata directly - Optimize MetadataDependencyExpander with indexed lookups Performance improvement: ~56% faster for filtered test runs (1366ms → 596ms in benchmarks with 301 types filtered to 1) Co-Authored-By: Claude Opus 4.5 <[email protected]>
7c0d242 to
067f1f2
Compare
|
Fixed the method overload ambiguity:
The existing method already had proper error handling and Performance optimization is retained - verified that filtered test runs still use the filter-aware |
SummaryThis PR adds filter-aware pre-filtering optimization to test discovery, using filter hints to skip non-matching test sources by type before materializing metadata, plus O(1) indexed dependency lookup to replace O(n) scanning. Critical IssuesNone found ✅ ObservationsDual-Mode Implementation ✅The changes correctly implement dual-mode support:
Both paths maintain behavioral equivalence as required. Performance OptimizationsTwo significant improvements:
Design Quality
Minor Observations
Verdict✅ APPROVE - No critical issues. The implementation is sound, follows TUnit's dual-mode requirements, and delivers meaningful performance improvements without breaking changes. |
The GenerateDynamicTests method was not handling custom DisplayName from IDynamicTestMetadata, causing tests like DynamicTestDisplayNameTests to fail. This was an oversight in PR #4058 which added DisplayName support to BuildTestsFromSingleMetadataAsync but missed GenerateDynamicTests. Changes: - Extract dynamicTestMetadata at the start for consistent access - Use dynamicTestMetadata?.DisplayName ?? metadata.TestName for display name - Set context.Metadata.DisplayName when custom display name is specified Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
Fixed the CI test failures. The failing tests were Root cause: The Fix: Updated
All dynamic tests now pass locally (18/18). |
SummaryImplements filter-aware test collection that pre-filters test sources by type before metadata materialization, improving filtered test run performance by 56%. Critical IssuesNone found ✅ AnalysisTUnit Rule Compliance✅ Dual-Mode Implementation
✅ Performance First
✅ AOT Compatible
Code QualityInterface Design (ITestDataCollector.cs:17-24) DisplayName Support (TestBuilderPipeline.cs:165-237)
Regex Usage Note (MetadataFilterMatcher.cs:99) Previous Comments AddressedPer your comments:
SuggestionsOptional: String manipulation over Regex // MetadataFilterMatcher.cs:99 - Replace regex with simple string ops
if (filterString.Contains('['))
{
var bracketIndex = filterString.IndexOf('[');
filterString = filterString.Substring(0, bracketIndex);
}This avoids regex compilation overhead and is more AOT-friendly, but the impact is negligible since this isn't a hot path. Verdict✅ APPROVE - Excellent performance optimization that follows all TUnit critical rules. The 56% improvement for filtered runs and 77x faster metadata collection are significant wins. Implementation is clean, maintains dual-mode compatibility, and all identified issues have been resolved. |
The TestMetadataEqualityComparer was incorrectly deduplicating dynamic tests that targeted the same method but had different argument values. This happened because the comparer only compared TestClassType, TestMethodName, and TestName - not the DynamicTestIndex which uniquely identifies each dynamic test instance. This fix adds DynamicTestIndex comparison for IDynamicTestMetadata in both Equals() and GetHashCode() methods, ensuring that multiple dynamic tests targeting the same method are not incorrectly merged in the HashSet used by MetadataDependencyExpander.ExpandToIncludeDependencies. Fixes the DynamicTestIndexTests failure where 5 tests were expected but only 1 was discovered. Co-Authored-By: Claude Opus 4.5 <[email protected]>
SummaryImplements filter-aware test collection that pre-filters test sources by type before metadata materialization, improving filtered test run performance by 56%. Critical IssuesNone found ✅ AnalysisTUnit Rule Compliance ✅Dual-Mode Implementation
Performance-First Approach
AOT Compatibility
Code QualityInterface Extension (ITestDataCollector.cs:17-24) DisplayName Fix (TestBuilderPipeline.cs:165-237)
Dependency Expansion Optimization (MetadataDependencyExpander.cs:83-197)
TestDiscoveryService Integration (TestDiscoveryService.cs:77-88) var allMetadata = await _testBuilderPipeline.CollectTestMetadataAsync(testSessionId);
var tests = await _testBuilderPipeline.BuildTestsStreamingAsync(..., metadataFilter: ..., ...)To: var allMetadata = await _testBuilderPipeline.CollectTestMetadataAsync(testSessionId, filter);
var tests = await _testBuilderPipeline.BuildTestsFromMetadataAsync(metadataToInclude, buildingContext, ...)This avoids collecting metadata twice - once for filtering, once for building. Smart optimization. Previous Review StatusAll issues from previous reviews have been addressed:
Minor Observations
Performance ImpactPer the PR description:
These are significant improvements that align with TUnit's performance-first principle. Verdict✅ APPROVE - Excellent performance optimization that follows all TUnit critical rules. The implementation is clean, maintains dual-mode compatibility, properly handles edge cases, and all identified issues from previous reviews have been resolved. The 56% improvement for filtered runs and 77x faster metadata collection are meaningful wins for the test framework. |
Summary
--treenode-filter)Key Changes
FilterHints struct (
MetadataFilterMatcher.cs): Extracts assembly, namespace, class, and method name hints from TreeNodeFilter for pre-filteringCouldTypeMatch method: Quickly filters types based on hints without full metadata processing
Filter-aware collection (
ITestDataCollector.cs,AotTestDataCollector.cs): New overload that accepts filter and pre-filtersSources.TestSourcesby typeBuildTestsFromMetadataAsync (
TestBuilderPipeline.cs): New method to build tests from pre-collected metadata, avoiding redundant collectionTestDiscoveryService optimization: Uses
BuildTestsFromMetadataAsyncto avoid collecting metadata twiceMetadataDependencyExpander optimization: Added indexed lookups for O(1) dependency resolution
Performance Results
Test plan
🤖 Generated with Claude Code