Repository navigation
Description
Part 1 of #7205, split from #7328. That PR went over the issue-pr-loop rework budget (20 automated review rounds, and its latest review still had a blocking finding). Its branch issue-7205-di-scope-dispose (head b1a2ba27d2) has commits to reuse.
Scope
Deliver the OnDispose subscriptions that data sources make on the per-iteration TestBuilderContext to the test built from that row, and raise them once per test.
TestBuilderContext.ShareEventsWith(internal, lazy, likeShareStateBagWith).- In both the source-generated and reflection paths of
TestBuilder, the class row's first fetch (fix(engine): reuse the first class-data fetch for the first test of a class row #7195) runs against its own context, and its events travel withUnclaimedClassRowto the test that takes it. A row handed back withReturnkeeps its events. OnDisposeis raised once per test inTestCoordinator's final cleanup, not once per attempt (AbstractExecutableTest.TryClaimOnDispose,TestOnDisposeRaiser.RaiseOnceAsync). This keeps retries working. Skipped, dependency-skipped, cancelled-before-start and circular-dependency-removed tests also raise it (TestScheduler,TestRunner).- Document the behavior change in
ITestEvents.OnDispose,docs/docs/writing-tests/dependency-injection.mdand the PR description, so it reaches the release notes. Handlers used to run once per attempt, before the instance was disposed. They now run once per test, after it.
Out of scope (separate issues)
- The lent first fetch for instance method data sources (
UnclaimedClassRow.LendToTemporaryInstance) belongs to the session-lifetime sub-issue. In this part, leave its events wheremainleaves them (not delivered to a test). Do not move them to the first test. That is the blocking Codex finding on fix(engine): deliver builder-context events to the test built from each row #7328: the first test'sOnDisposedisposes a constructor-injected service that the temporary instance returned in later method rows. - Externally owned scope services (double disposal by the object tracker): see the sibling sub-issue.
- Failed data-row tests: Failed data-row tests drop builder-context events, so DI scopes of failed rows are never disposed #7326.
Files
src/TUnit.Core/TestBuilderContext.cs, src/TUnit.Core/AbstractExecutableTest.cs, src/TUnit.Core/Interfaces/ITestEvents.cs, src/TUnit.Engine/Building/TestBuilder.cs (row-events plumbing only), src/TUnit.Engine/Services/TestExecution/TestCoordinator.cs, src/TUnit.Engine/Services/TestExecution/TestOnDisposeRaiser.cs (RaiseOnceAsync), src/TUnit.Engine/Scheduling/TestScheduler.cs, src/TUnit.Engine/Scheduling/TestRunner.cs, docs, and the matching tests/TUnit.TestProject/Bugs/_7205 and tests/TUnit.Engine.Tests/Issue7205Tests.cs cases.
Acceptance criteria
- A class-level and a method-parameter
DependencyInjectionDataSourceAttribute<TScope>scope is created once per test and disposed once, in source-generated and reflection modes. This includes[Repeat],[Retry](the retry does not see a disposed scope) and[Skip]tests. - Tests that never reach the coordinator still dispose their scope once.
- Keep the PR small: no session-level deferral machinery and no ownership changes.
Activity
fix(engine): release unstarted tests' scopes on every scheduler exit …
fix(engine): release unstarted scopes when grouping fails (#7381)
fix(engine): preserve DI disposal ownership on failed rows (#7381, #7382
fix(engine): deliver row builder-context events to the test and raise…