Repository navigation
fix(engine): invoke OnTestRegistered on property-injected data sources - #7292
Conversation
Registered receivers ran once, before argument registration resolved injected property values, so a shared fixture that implements ITestRegisteredEventReceiver was skipped when injected as a property. Run a second receiver pass after argument registration, sharing the identity set so receivers that already ran are not invoked twice. Fixes #7290
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Registration receiver phases src/TUnit.Core/Interfaces/ITestRegisteredEventReceiver.cs, docs/docs/writing-tests/event-subscribing.md, src/TUnit.Engine/Services/TestFilterService.cs |
The receiver context and invocation logic are shared across registration phases. After argument registration succeeds, the service invokes newly available property receivers without invoking previously processed receivers again. The interface remarks and documentation describe callback ordering and data-source timing. |
Property receiver behavior tests tests/TUnit.TestProject/Bugs/_7290/Tests.cs, tests/TUnit.Engine.Tests/RegisteredReceiverInjectedProperty7290Tests.cs |
Added tests check parallel limiting, registration counts, shared-instance identity, concurrency, and skipping. The engine test asserts the completed run has 6 tests: 5 passed, 0 failed, and 1 not executed. |
Priority:
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Bug fix · Severity of issue fixed: Medium
Merge Risk: 
Minimal · up to 8385d
-
Property-injected receivers gain registration callbacks; no merge-blocking issue was established.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passed-
Full details: Linked Issues check
-
Explanation
Issue
#7290requires property-injected data-source values that implementITestRegisteredEventReceiverto receiveOnTestRegisteredbefore scheduling.TestFilterService.RegisterTestperforms a second receiver pass after successful execution-time argument registration, rebuilds the receiver list, and shares a reference-identity set with the first pass. This invokes property receivers, prevents duplicate callbacks for shared constructor and property instances, and applies actions such asSetParallelLimiterandSetSkipped. The added tests cover property injection, limiter behavior, identity deduplication, and registration-time skipping.
Full details: Out of Scope Changes check
-
Explanation
The changed files remain connected to issue
#7290. The engine changes implement the second receiver pass. The interface and event-subscribing documentation describe the resulting timing and behavior. The added engine and test-project tests verify the issue behavior. No unrelated change is shown in the reviewed diff.
-
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 4 functions across 4 files. (1 skipped: 1 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches: 💡 1
-
📝 Generate docstrings: 💡
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
A rabbit checks the callback queue.
Property receivers join the view.
One shared context follows through.
A limiter keeps the tests in line.
A skipped test stops before its time.
Comment @coderabbitai help to get the list of available commands.
Review of #7292I read the diff only; I did not build it or run any tests. The skill runner errored, so this is a manual review. The approach is sound. It fixes the cause: property values only exist after Minor points, none blocking:
Overall this looks good to merge once point 2 is confirmed. |
[Medium impact] The PR appears safe to merge; no actionable issues were found. SummaryThe PR calls
|
Fixes #7290
Problem
TestFilterService.RegisterTestinvokesITestRegisteredEventReceivers once, before argument registration. That order is deliberate: aSkipAttributecan skip a test before expensive data sources are created. Injected property values are only resolved later, inRegisterTestArgumentsAsync, so a shared fixture receivedOnTestRegisteredas a constructor or method argument but never as an injected property. A fixture that calledSetParallelLimiterlimited constructor consumers but not property consumers.Fix
After argument registration succeeds, and when the test has injected properties,
RegisterTestruns a second receiver pass. Argument registration already drops the receiver caches (#6554), so the rebuilt list includes the property values. The second pass shares the first pass's reference-identity set, so receivers that already ran (attributes, constructor and method arguments, installed executors) are not invoked twice. The receiver and executor-drain loop moved into a helper used by both passes.Behavior notes, documented in
event-subscribing.mdand onITestRegisteredEventReceiver:Order.SetSkipped. The shared objects already exist at that point, because the receiver is one of them.TestCoordinatorhandles the skip as it does for any registration-time skip.The change is in the shared registration path, so it covers source-gen and reflection modes with one implementation.
ParallelLimiteris read byTestRunnerat execution time, so a limiter set in the second pass takes effect.Tests
tests/TUnit.TestProject/Bugs/_7290/Tests.cs:[Repeat(3)]: assertsParallelism.LimiterisOneAtATime, exactly oneOnTestRegisteredper test, and a maximum of one test running at once.SetSkipped: the test body throws, so the test passes only if it is skipped.tests/TUnit.Engine.Tests/RegisteredReceiverInjectedProperty7290Tests.csasserts 6 total, 5 passed, 1 skipped.Local results:
Value is of type null, not OneAtATimeand the skip test executing.RegisteredReceiverInjectedProperty7290Tests,PartialInjectionFailure6554TestsandExpectedStateTests.Passall passed. AOT mode is skipped locally and runs in CI.Bugs._6557,DynamicSkipReasonTestsand*ParallelLimit*(35 tests) passed.Bugs._6554has its one intentional registration failure.Summary by CodeRabbit