Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Flaky NRE in AfterEvery(Class) hooks: dynamic test's TestContext is visible in ClassHookContext.Tests before TestDetails is assigned #6180

Copy link
Copy link

Description

@thomhurst
Issue body actions

Symptom

Flaky CI failure (ubuntu leg, run 27100880280, PR #6178 — unrelated changes):

Error executing After hooks for TUnit.TestProject.DynamicTests.Runtime(...).SomeMethod(...):
TUnit.Core.Exceptions.AfterClassException: AfterEveryClass hook failed: Object reference not set to an instance of an object.
 ---> System.NullReferenceException
   at TUnit.TestProject.AfterTests.AfterEveryClassHooks.AfterEveryClass(ClassHookContext context)

The hook dereferences test.Metadata.TestDetails.TestName while iterating context.Tests (TUnit.TestProject/AfterTests/AfterEveryClassTests.cs:10).

Root cause

  1. ContextProvider.CreateTestContext (TUnit.Core/ContextProvider.cs:94) calls classContext.AddTest(testContext) immediately after constructing the TestContext.
  2. TestDetails is null!-initialized (TUnit.Core/TestContext.cs:310) and only assigned later by the builder (TUnit.Engine/Building/TestBuilder.cs:1086, TestBuilderPipeline.cs:274/401/481/536).
  3. So there is a window where a partially-built TestContext (with TestDetails == null) is observable via ClassHookContext.Tests.

For statically discovered tests this window closes before any hooks run. For dynamic tests (AddDynamicTest) it doesn't: DynamicTests.Runtime.BuildTests registers multiple dynamic tests at runtime into the same ClassHookContext (keyed by Type). When one dynamic test finishes and triggers AfterEvery(Class) while a sibling dynamic test's context is mid-construction, the hook observes TestDetails == null → NRE.

Possible fixes

  • Assign TestDetails before the context becomes visible (e.g. pass into the TestContext ctor or set before AddTest), or
  • Defer classContext.AddTest(...) until the test is fully built, or
  • Have ClassHookContext.Tests filter out contexts whose TestDetails is not yet set.

First option seems most robust — it removes the partially-initialized published state rather than masking it.

Applies to both reflection and source-gen modes (shared ContextProvider/builder path).

Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.