-
-
Notifications
You must be signed in to change notification settings - Fork 106
fix: don't run IAsyncInitializer during discovery phase #3996
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
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 fixes issue #3992 by preventing IAsyncInitializer.InitializeAsync() from being called during test discovery. The fix introduces a new method InjectPropertiesAsync that performs property injection without triggering async initialization, deferring IAsyncInitializer calls to test execution time.
Key Changes:
- Added
InjectPropertiesAsyncmethod toObjectLifecycleServicefor property injection without async initialization - Updated
TestBuilderto useInjectPropertiesAsyncinstead ofEnsureInitializedAsyncduring discovery phase - Added regression test to verify
IAsyncInitializeris not called during discovery
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| TUnit.TestProject/Bugs/3992/IAsyncInitializerDiscoveryTests.cs | Regression test verifying IAsyncInitializer is only called during execution, not discovery |
| TUnit.Engine/Services/ObjectLifecycleService.cs | Added new InjectPropertiesAsync method that injects properties without calling IAsyncInitializer |
| TUnit.Engine/Building/TestBuilder.cs | Updated three call sites to use InjectPropertiesAsync instead of EnsureInitializedAsync during discovery |
| if (obj == null) | ||
| { | ||
| throw new ArgumentNullException(nameof(obj)); | ||
| } |
Copilot
AI
Dec 6, 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.
Redundant null check: the generic constraint where T : notnull already ensures obj cannot be null at compile time. This check is unnecessary and can be removed.
| if (obj == null) | |
| { | |
| throw new ArgumentNullException(nameof(obj)); | |
| } |
| [Test] | ||
| [ClassDataSource<DataSourceWithAsyncInit>] | ||
| public async Task DataSource_InitializeAsync_OnlyCalledDuringExecution(DataSourceWithAsyncInit dataSource) | ||
| { | ||
| // Verify that the data source was initialized | ||
| await Assert.That(dataSource.IsInitialized).IsTrue(); | ||
|
|
||
| // Verify that InitializeAsync was called (at least once during execution) | ||
| await Assert.That(_initializationCount).IsGreaterThan(0); | ||
|
|
||
| Console.WriteLine($"Test execution confirmed: InitializeAsync was called {_initializationCount} time(s)"); | ||
| } |
Copilot
AI
Dec 6, 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.
Test coverage gap: This test only covers method parameter data sources ([ClassDataSource<T>]). Consider adding a test case for property-based data sources as well, since properties can also use data source attributes and implement IAsyncInitializer.
Example:
public class PropertyDataSourceWithAsyncInit : IAsyncInitializer
{
public bool IsInitialized { get; private set; }
public Task InitializeAsync() { IsInitialized = true; return Task.CompletedTask; }
}
[PropertyDataSource<PropertyDataSourceWithAsyncInit>]
public PropertyDataSourceWithAsyncInit PropertyData { get; set; }
[Test]
public async Task PropertyDataSource_InitializeAsync_OnlyCalledDuringExecution()
{
await Assert.That(PropertyData.IsInitialized).IsTrue();
}
Fixes #3992