-
-
Notifications
You must be signed in to change notification settings - Fork 108
Better exception messages when injected data sources throw #4110
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
Better exception messages when injected data sources throw #4110
Conversation
Code Review - PR #4110: Better exception messages when injected data sources throwOverviewThis PR addresses issue #4049 by improving error messages when data sources fail during initialization. The change propagates exceptions from nested initializer property access instead of silently swallowing them. Strengths
Concerns and Questions1. Breaking Change in Error Handling Behavior (Severity: Medium)The previous code caught exceptions and continued discovery, but the new code propagates exceptions immediately. Impact: This is a behavioral change. Previously, if one data source property failed, discovery would continue and potentially discover other valid tests. Now, a single failing property stops all discovery for that object graph. Questions:
2. DataSourceException API Design (Severity: Low)The FromNestedFailure factory method sets DataSourceName to empty string, which feels like a compromise. Suggestions:
3. Dual-Mode Implementation Question (Severity: Medium)Per CLAUDE.md Rule 1, all changes must work identically in both execution modes. The tests use InvokableTestBase which is excellent. However:
Questions:
Verification needed: Can you confirm that the source-generated mode also propagates these exceptions correctly? Suggestions
Pre-Commit Checklist ReviewBased on CLAUDE.md requirements:
Recommendations
Overall AssessmentCode Quality: 4/5 | Test Coverage: 5/5 | Documentation: 4/5 This is a solid improvement that makes debugging much easier! The main concern is ensuring dual-mode parity and considering the behavioral change impact. Once concern 3 is verified, this looks ready to merge. Great work on the comprehensive test coverage! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR improves error handling and reporting when data sources or their nested dependencies fail during initialization. Previously, property access failures during object graph discovery were silently collected for diagnostics but didn't cause tests to fail. Now, these failures are propagated as DataSourceException with detailed context about which property and type failed, ensuring developers receive clear feedback when their data sources are misconfigured.
Key Changes
- Exception propagation behavior changed from swallowing to throwing for property access failures on
IAsyncInitializerproperties - Added factory method
DataSourceException.FromNestedFailure()to create exceptions with custom messages - Added comprehensive test coverage for both direct and nested initializer failures across multiple test modes
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
TUnit.Core/TestBuilder/TestBuilderException.cs |
Added FromNestedFailure() factory method and private constructor to support custom error messages for nested dependency failures |
TUnit.Core/Discovery/ObjectGraphDiscoverer.cs |
Changed exception handling to propagate failures with contextual information instead of silently collecting them |
TUnit.TestProject/Bugs/4049/InitializerExceptionPropagationTests.cs |
Added integration test verifying that direct InitializeAsync() failures properly fail tests |
TUnit.TestProject/Bugs/4049/NestedInitializerExceptionPropagationTests.cs |
Added integration test verifying that nested property access failures properly fail tests |
TUnit.Engine.Tests/DataSourceExceptionPropagationTests.cs |
Added engine tests validating error message content and test failure behavior across multiple test modes |
| private DataSourceException(string message, Exception innerException, bool isCustomMessage) | ||
| : base(message, innerException) | ||
| { | ||
| DataSourceName = string.Empty; | ||
| } |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unused parameter 'isCustomMessage' is accepted but never used in the constructor body. If this parameter is intended for future use or to disambiguate constructor overloads, consider documenting its purpose. Otherwise, remove it from the signature.
| $"Failed to access property '{property.Name}' on type '{type.Name}' during object graph discovery. " + | ||
| $"This may indicate that a data source or its nested dependencies failed to initialize. " + | ||
| $"See inner exception for details.", | ||
| ex); |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message construction spans multiple lines but uses string concatenation which creates multiple temporary strings. Consider using string interpolation for better readability and performance, or using a single multi-line string. For example: $"Failed to access property '{property.Name}' on type '{type.Name}' during object graph discovery. This may indicate that a data source or its nested dependencies failed to initialize. See inner exception for details."
| $"Failed to access property '{property.Name}' on type '{type.Name}' during object graph discovery. " + | |
| $"This may indicate that a data source or its nested dependencies failed to initialize. " + | |
| $"See inner exception for details.", | |
| ex); | |
| $"Failed to access property '{property.Name}' on type '{type.Name}' during object graph discovery. This may indicate that a data source or its nested dependencies failed to initialize. See inner exception for details.", | |
| ex); | |
Code Review - PR #4110: Better exception messages when injected data sources throwOverviewThis PR improves error handling when data sources fail during initialization, specifically addressing issue #4049 where exceptions in nested IAsyncInitializer properties were silently swallowed. Strengths
CRITICAL ISSUE: Dual-Mode Implementation MissingBLOCKER: Per CLAUDE.md Rule 1, ALL changes must work in both execution modes:
The source generator needs similar exception wrapping in generated code. Code Quality Issues1. Breaking Behavior Change 2. OperationCanceledException Handling 3. Design: DataSourceName = string.Empty 4. Redundant Error Logging Potential Bug: Original Issue Not Fully AddressedIssue #4049 was about property getters being called eagerly (causing WebApplicationFactory to build prematurely). This PR makes exceptions propagate but doesn't stop ALL property getters from being called during discovery. The root problem remains: TUnit still calls every property getter, not just those with ClassDataSource attributes. RecommendationsMust Fix:
Should Fix: Consider: Happy to help implement the source generator side if needed! |
Code Review: Better Exception Messages for Injected Data SourcesSummary: This PR improves error handling and reporting when data sources (especially nested IAsyncInitializer types) fail during initialization. The implementation correctly follows TUnit's dual-mode architecture and AOT requirements. ✅ Strengths1. Excellent Dual-Mode Implementation
2. Strong AOT/Trimming Compliance
3. Clean Architecture
4. Performance Considerations
|
🔍 Issues & SuggestionsCritical Issue: Exception Handling Changes BehaviorLocation: Problem: The PR changes exception handling from "swallow and continue" to "propagate and fail". While this is the intended fix, it's a breaking behavioral change that could affect existing tests. Before: Exceptions were caught and logged but discovery continued Impact: Any existing tests with data sources that throw during property access will now fail instead of silently continuing with null values. Recommendation:
Minor Issue:
|
Enhancement: Consider Caching in Source GeneratorLocation: The source generator looks up the Note: Not critical since this only runs at compile-time. Minor Style Issue: LINQ in Source GeneratorLocation: The code uses LINQ to filter properties. From CLAUDE.md Rule 4: "Minimize allocations in hot paths... avoid LINQ" Counter-argument: Source generators run at compile-time, not runtime, so LINQ is acceptable here. This is NOT a hot path. Verdict: ✅ This is fine - the rule applies to runtime hot paths, not build-time code. 📝 Test CoverageExcellent test coverage for the new functionality:
Tests follow best practices:
|
🎯 Compliance with TUnit Development Guide✅ Rule 1 (Dual-Mode): Fully compliant - both paths implemented Code Style: ✅ Modern C# syntax, proper documentation, correct patterns 🏁 Final VerdictOverall Assessment: ⭐⭐⭐⭐½ (4.5/5) Pros:
Cons:
Recommendation: ✅ Approve with minor suggestions This is high-quality work that correctly implements exception propagation while maintaining TUnit's architectural principles. The behavioral change is intentional and improves the user experience by surfacing initialization failures instead of silently swallowing them. 💡 Optional Future Enhancements
Great work on this PR! The implementation is solid and follows TUnit conventions. The minor issues mentioned are non-blocking suggestions for improvement. |
No description provided.