Skip to content

Conversation

@thomhurst
Copy link
Owner

@thomhurst thomhurst commented Jan 29, 2026

Summary

Fixes #4584

This PR fixes two issues:

Issue 1: Dependencies not available in After(TestDiscovery) hooks

Dependencies were not populated when After(TestDiscovery) hooks ran because PopulateDependencies was called during the per-test registration loop, which happens after hooks execute.

Fix: Populate TestContext._dependencies for ALL tests before After(TestDiscovery) hooks run.

Issue 2: OnTestRegistered called twice (bug discovered during investigation)

ITestRegisteredEventReceiver.OnTestRegistered was being called twice:

  1. In InvokePostResolutionEventsAsync for ALL tests
  2. In TestFilterService.RegisterTest for FILTERED tests

This caused indeterministic behavior - the first call saw empty dependencies (before population), made a skip decision, then the second call saw populated dependencies but the decision was already made.

Fix: Remove OnTestRegistered from InvokePostResolutionEventsAsync. Registration events now only fire in TestFilterService.RegisterTest for filtered tests. This is semantically correct:

  • Discovery events (OnTestDiscovered) → ALL tests
  • Registration events (OnTestRegistered) → FILTERED tests only (tests that will run)

Changes

  • TestContext.Dependencies.cs: Add _dependenciesPopulated flag for idempotent population
  • ITestBuilder.cs: Add PopulateDependenciesOnly() method
  • TestBuilder.cs:
    • Implement PopulateDependenciesOnly() with idempotency
    • Remove InvokeTestRegisteredReceiversAsync() from InvokePostResolutionEventsAsync()
    • Delete unused InvokeTestRegisteredReceiversAsync() method
  • TestBuilderPipeline.cs: Add PopulateAllDependencies() batch method
  • TestDiscoveryService.cs: Call PopulateAllDependencies() before After(TestDiscovery) hooks
  • TestFilterService.cs: Add InvalidateDisplayNameCache() after registration events (moved from removed code)

Test plan

  • Added comprehensive tests in TUnit.TestProject/Bugs/4584/
    • Direct class-level dependencies visible in hook
    • Method-level dependencies visible in hook
    • Transitive dependencies visible in hook
    • Skip attribute pattern (mirrors user's FocusAssemblyAttribute)
    • Multiple focused tests with shared dependencies
    • Tests with no dependencies
  • Existing dependency tests pass
  • Existing skip tests pass
  • Test discovery hook tests pass

@claude
Copy link
Contributor

claude bot commented Jan 29, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@thomhurst thomhurst force-pushed the fix/4584-dependencies-in-after-test-discovery-hook branch from c388845 to d84f409 Compare January 29, 2026 18:34
@thomhurst thomhurst force-pushed the fix/4584-dependencies-in-after-test-discovery-hook branch from d84f409 to 05e6385 Compare January 29, 2026 18:37
@thomhurst thomhurst force-pushed the fix/4584-dependencies-in-after-test-discovery-hook branch from 05e6385 to 0f13b50 Compare January 29, 2026 18:39
@thomhurst thomhurst force-pushed the fix/4584-dependencies-in-after-test-discovery-hook branch from 0f13b50 to cccdbe4 Compare January 29, 2026 18:51
This fixes two issues:

1. Dependencies were not available in After(TestDiscovery) hooks because
   PopulateDependencies was called during per-test registration, after hooks.
   Now dependencies are populated for ALL tests before hooks run.

2. OnTestRegistered was being called twice - once in InvokePostResolutionEventsAsync
   (for all tests) and again in TestFilterService.RegisterTest (for filtered tests).
   Now OnTestRegistered only fires once, in TestFilterService.RegisterTest, which
   is the correct semantic: registration events fire for tests that will run.

Changes:
- Add _dependenciesPopulated flag to TestContext for idempotent population
- Add PopulateDependenciesOnly() to ITestBuilder/TestBuilder
- Add PopulateAllDependencies() to TestBuilderPipeline
- Call PopulateAllDependencies() before After(TestDiscovery) hooks
- Remove InvokeTestRegisteredReceiversAsync from InvokePostResolutionEventsAsync
  (discovery events still fire for all tests, registration events for filtered only)
@thomhurst thomhurst force-pushed the fix/4584-dependencies-in-after-test-discovery-hook branch from cccdbe4 to 1970efa Compare January 29, 2026 18:53
@thomhurst thomhurst merged commit b66bea6 into main Jan 29, 2026
13 checks passed
@thomhurst thomhurst deleted the fix/4584-dependencies-in-after-test-discovery-hook branch January 29, 2026 19:20
This was referenced Jan 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Focus tests

2 participants