Skip to content

fix(engine): run lifecycle hooks before test class construction (#6192)#6195

Merged
thomhurst merged 3 commits into
mainfrom
fix/6192-hooks-before-constructor
Jun 8, 2026
Merged

fix(engine): run lifecycle hooks before test class construction (#6192)#6195
thomhurst merged 3 commits into
mainfrom
fix/6192-hooks-before-constructor

Conversation

@thomhurst

Copy link
Copy Markdown
Owner

Fixes #6192.

Problem

The documented lifecycle contract says hooks run before test-class instantiation, but the constructor was running before BeforeEveryAssembly/BeforeEveryClass (and Before(Assembly)/Before(Class)).

Root cause: TestCoordinator called CreateInstanceAsync() (the constructor) before TestExecutor.ExecuteAsync(), and the before-hooks live inside ExecuteAsync (GetOrCreateBeforeAssemblyTask/GetOrCreateBeforeClassTask). So construction always preceded the hooks. The repro has no data sources, so this is purely execution-time ordering — the "constructor twice" in the report is just the two tests, each constructed once before the hooks.

Fix

The before-hook tasks are already cached/idempotent in BeforeHookTaskCache, so they can be awaited earlier without re-running. New TestExecutor.EnsureClassAndAssemblyHooksExecutedAsync runs the cached Before(TestSession/Assembly/Class) tasks, and TestCoordinator calls it immediately before CreateInstanceAsync on both the no-retry fast path and the retry path. ExecuteAsync's subsequent hook awaits become no-ops; the non-cached FirstTestIn* event receivers and RegisterAfter* pairs stay exactly where they were.

The helper replays the RestoreExecutionContext chain between hook awaits (mirroring ExecuteAsync) so AsyncLocals still flow BeforeTestSessionBeforeAssemblyBeforeClass.

Tests

  • New self-validating regression test Bugs/6192/Bug6192Tests.cs: the constructor throws if BeforeEvery(Assembly)/BeforeEvery(Class) have not yet run. Fails before the fix, passes after.
  • Verified no regression across the lifecycle/hook suites (Bugs/1914 AsyncLocal flow, BeforeTests/*, Bugs/4432 constructor injection, Bugs/_2804 hook cleanup), in both source-generated and reflection modes.

Engine-only change — no source-generator or snapshot changes.

Before(TestSession/Assembly/Class) hooks (and their BeforeEvery
counterparts) were executed inside TestExecutor.ExecuteAsync, which
TestCoordinator only invoked AFTER calling CreateInstanceAsync. As a
result the test class constructor ran before BeforeEveryAssembly /
BeforeEveryClass, violating the documented lifecycle contract that
hooks run before instantiation.

Hoist the cached Before(Session/Assembly/Class) hook tasks ahead of
CreateInstanceAsync via a new TestExecutor.EnsureClassAndAssemblyHooks
ExecutedAsync helper, called on both the no-retry fast path and the
retry path. The hook tasks are cached in BeforeHookTaskCache, so
ExecuteAsync's later awaits are no-ops; the helper replays the
RestoreExecutionContext chain so AsyncLocals still flow between hooks.

Adds a self-validating regression test under Bugs/6192 that asserts the
constructor observes BeforeEvery(Assembly)/BeforeEvery(Class) as already
run. Verified in both source-generated and reflection modes.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — fix(engine): run lifecycle hooks before test class construction (#6192)

Summary

This is a clean, well-motivated fix. The root cause analysis in the PR description is accurate — TestCoordinator called CreateInstanceAsync() before ExecuteAsync(), but all Before* hooks live inside ExecuteAsync. The caching approach is the right architectural lever here. No snapshot or source-gen changes are needed.


Correctness Concerns

1. EnsureClassAndAssemblyHooksExecutedAsync duplicates the session hook, creating subtle divergence risk

EnsureClassAndAssemblyHooksExecutedAsync re-implements the BeforeTestSession await that already exists in EnsureTestSessionHooksExecutedAsync, instead of calling that method:

// EnsureTestSessionHooksExecutedAsync (line 52) — existing method
await _beforeHookTaskCache.GetOrCreateBeforeTestSessionTask(...);
_afterHookPairTracker.RegisterAfterTestSessionHook(...);  // ← this part is missing below

// EnsureClassAndAssemblyHooksExecutedAsync (line 78) — new method
await _beforeHookTaskCache.GetOrCreateBeforeTestSessionTask(...);  // duplicated
// NO RegisterAfterTestSessionHook call

The RegisterAfterTestSessionHook call is intentionally omitted because the PR description says "After-hook pair registration stays single-sourced in ExecuteAsync". That's correct for the cancellation path — but it means the ordering contract between BeforeTestSession and the After registration depends on ExecuteAsync being called afterward, which is always true on the happy path. This is fragile: if a future change causes ExecuteAsync not to be called (e.g. a new skip path after EnsureClassAndAssemblyHooksExecutedAsync), the After hooks won't be registered.

Suggested improvement: Call EnsureTestSessionHooksExecutedAsync from within EnsureClassAndAssemblyHooksExecutedAsync rather than duplicating the session-hook await:

public async ValueTask EnsureClassAndAssemblyHooksExecutedAsync(AbstractExecutableTest test, CancellationToken cancellationToken)
{
    // Reuse the existing method for TestSession; it's idempotent.
    // After-hook registration is intentionally still deferred to ExecuteAsync.
    await _beforeHookTaskCache.GetOrCreateBeforeTestSessionTask(
        ct => _hookExecutor.ExecuteBeforeTestSessionHooksAsync(ct),
        cancellationToken).ConfigureAwait(false);
    // ... rest unchanged
}

This is already what the code does, so the concern is about the omitted RegisterAfterTestSessionHook. Either a comment explaining why the After hook registration is safe to defer, or a guard (e.g. checking _afterHookPairTracker.IsTestSessionHookRegistered) before CreateInstanceAsync, would make the invariant explicit and harder to break.

2. ExecuteAsync still calls EnsureTestSessionHooksExecutedAsync separately from the new method (line 113)

ExecuteAsync calls EnsureTestSessionHooksExecutedAsync (which wraps GetOrCreateBeforeTestSessionTask) and later the same cache key is hit again via the assembly/class hook path that was already pre-run. This is intentional (cached = no-op), but now there are three GetOrCreateBeforeTestSessionTask call sites in the same class (lines 55, 78, 113 — where 55 and 78 are different paths, 113 is in ExecuteAsync). Adding a code comment on line 113 noting that the task is already complete when called from TestCoordinator would reduce confusion for future readers.


Test Coverage

3. Regression test doesn't cover Before(Class) / Before(Assembly) (non-BeforeEvery) hooks

The test in Bug6192Tests.cs checks [BeforeEvery(Class)] and [BeforeEvery(Assembly)] via static booleans, but the PR description says the bug affects Before(Assembly) / Before(Class) (non-BeforeEvery) hooks too. Since those also go through GetOrCreateBeforeAssemblyTask/GetOrCreateBeforeClassTask, they are covered by the fix — but are not covered by the regression test. Adding a test variant using [Before(Assembly)] / [Before(Class)] would make the contract explicit.

4. No retry-path coverage

The fix applies to both the no-retry fast path (line 134) and the retry path (line 360 in ExecuteTestLifecycleAsync). The regression test doesn't have a [Retry] variant, so the retry path is untested by this PR. A simple [Retry(1)] copy of the test class would close this gap.


Minor / Observations

5. Return type inconsistency: Task vs ValueTask

EnsureTestSessionHooksExecutedAsync (line 52) returns Task, while the new EnsureClassAndAssemblyHooksExecutedAsync (line 73) returns ValueTask. Since the inner GetOrCreate* methods all return ValueTask, and the codebase consistently uses ValueTask for potentially-sync operations (per CLAUDE.md), EnsureTestSessionHooksExecutedAsync should probably also be ValueTask. This is a pre-existing inconsistency exposed by the new method, not introduced by this PR — worth a follow-up.


Overall Assessment

The fix is architecturally sound. The caching strategy is the right approach — pre-running the idempotent cached tasks before construction is cleaner than restructuring ExecuteAsync. The main concern (point 1) is about the implicit coupling between EnsureClassAndAssemblyHooksExecutedAsync and ExecuteAsync for the After-hook registration. A comment or an internal guard would make this invariant explicit. Points 3 and 4 are test-coverage gaps that are low risk given the existing hook test suite mentioned in the PR description, but worth tracking for completeness.

@codacy-production

codacy-production Bot commented Jun 8, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

…st allocations

Hoist the BeforeTestSession / BeforeAssembly hook-factory lambdas into
readonly fields instead of allocating a fresh closure on every call. These
run on the per-test hot path and the factory is only invoked on the first
cache miss, so the per-test allocation was pure waste. Reused across
EnsureTestSessionHooksExecutedAsync, EnsureClassAndAssemblyHooksExecutedAsync
and ExecuteAsync. Also inline the single-use testAssembly local.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: fix(engine): run lifecycle hooks before test class construction (#6192)

Overview

Clean, targeted fix for a real lifecycle-ordering bug: the test class constructor was running before Before(Assembly)/Before(Class) hooks, violating the documented contract. The root cause (construction happening in TestCoordinator before ExecuteAsync's cached hooks had a chance to run) is correctly identified, and the solution (a new idempotent pre-construction gate) is minimal and well-explained.


What's Good

  • Both code paths covered — the hook gate is applied to both the no-retry fast path and ExecuteTestLifecycleAsync, so there's no way to slip through.
  • Cached tasks mean no double-execution — leveraging the existing BeforeHookTaskCache idempotency means ExecuteAsync's subsequent awaits are genuine no-ops; no risk of hooks running twice.
  • AsyncLocal chain is mirrored — the RestoreExecutionContext calls inside EnsureClassAndAssemblyHooksExecutedAsync replicate the chain from ExecuteAsync, so AsyncLocals flow Session → Assembly → Class as before.
  • Cached factory delegates — pre-allocating _beforeTestSessionHookFactory / _beforeAssemblyHookFactory on construction to avoid per-call closure allocations is a correct micro-optimization on the hot path.
  • Self-validating regression test — the constructor-throws-if-hooks-not-run pattern will reliably catch regressions.

Potential Gap: Missing ClassContext.RestoreExecutionContext() After GetOrCreateBeforeClassTask

In ExecuteAsync (line ~157) the execution context chain continues:

await _beforeHookTaskCache.GetOrCreateBeforeClassTask(testClass, _hookExecutor, cancellationToken)...
// ... InvokeFirstTestInClassEventReceivers ...
executableTest.Context.ClassContext.RestoreExecutionContext();  // <-- restores class context for test body

EnsureClassAndAssemblyHooksExecutedAsync currently ends without calling test.Context.ClassContext.RestoreExecutionContext() after the class-hook task:

await _beforeHookTaskCache.GetOrCreateBeforeClassTask(testClass, _hookExecutor, cancellationToken)...
// ← No ClassContext.RestoreExecutionContext() here

Consequence: AsyncLocals written by a [Before(Class)] or [BeforeEvery(Class)] hook won't flow into the constructor, even though the hooks will have run before it. The fix guarantees ordering (issue #6192's core requirement), but constructors relying on AsyncLocals set in class-level hooks would silently not see them.

Whether this is an intentional scope decision ("#6192 only requires that hooks have run, not that their AsyncLocals reach the constructor") should be explicitly stated. If AsyncLocal propagation into constructors is ever expected, the fix to add at the end of EnsureClassAndAssemblyHooksExecutedAsync would be:

await _beforeHookTaskCache.GetOrCreateBeforeClassTask(testClass, _hookExecutor, cancellationToken).ConfigureAwait(false);
test.Context.ClassContext.RestoreExecutionContext(); // flow BeforeClass AsyncLocals into constructor

Minor: Regression Test Doesn't Cover Before(Class) / Before(Assembly) (Only BeforeEvery)

Bug6192Tests validates [BeforeEvery(Class)] and [BeforeEvery(Assembly)], but issue #6192's title also mentions Before(Assembly)/Before(Class). Given those go through the same cache path they should be fine, but a quick comment in the test noting this would help future readers understand why BeforeEvery coverage is sufficient.


Minor: Static Bool Fields Without volatile

Bug6192HookOrderProbe.BeforeEveryClassRan / BeforeEveryAssemblyRan are plain static bool fields. In practice the framework's task-caching ensures a happens-before edge, so this works. But marking them volatile (or using Interlocked) would make the memory model intent explicit.


Summary

The fix is correct and well-structured. The one gap worth a follow-up call-out is the missing ClassContext.RestoreExecutionContext() at the end of the new method — whether it's an intentional scope decision or an oversight should be confirmed, since it determines whether AsyncLocals from class hooks reach the constructor. Everything else looks solid.

…k AsyncLocals flow (#6192)

The pre-construction hook gate ran Before(Assembly)/Before(Class) hooks before the test class was constructed, but never restored the class ExecutionContext before construction. AsyncLocals captured by those hooks (via AddAsyncLocalValues) therefore reached the test body but not the constructor.

Restoring inside EnsureClassAndAssemblyHooksExecutedAsync does not work: the ambient ExecutionContext is reset when that async method returns to the caller. Restore ClassContext in TestCoordinator immediately before CreateInstanceAsync on both the fast and retry paths instead.

Also expand the regression test to cover Before(Class)/Before(Assembly) (not just BeforeEvery), the retry path, and AsyncLocal flow into the constructor; and make EnsureTestSessionHooksExecutedAsync return ValueTask for consistency.
@thomhurst

Copy link
Copy Markdown
Owner Author

Addressed the review feedback in c12d654:

Missing ClassContext.RestoreExecutionContext() (real bug, fixed). Confirmed: the gate ran the Before(Class) hook but the constructor then ran without the class ExecutionContext restored, so AsyncLocals a class-level hook opts into via AddAsyncLocalValues() reached the test body (ExecuteAsync line 157) but not the constructor.

Restoring at the end of EnsureClassAndAssemblyHooksExecutedAsync does not work — the ambient ExecutionContext is reset when that async method returns to its caller, so the restore is lost before CreateInstanceAsync runs. I verified this: a regression test asserting the AsyncLocal in the constructor still failed with the restore inside the gate method, and passed once moved. The restore now lives in TestCoordinator immediately before CreateInstanceAsync, on both the fast path and the retry path.

Test coverage gaps (fixed). Bug6192Tests now also covers [Before(Class)]/[Before(Assembly)] (not just BeforeEvery), and a new Bug6192RetryTests covers the retry path. Both assert AsyncLocal flow into the constructor, which is what guards the fix above.

Task vs ValueTask (fixed). EnsureTestSessionHooksExecutedAsync now returns ValueTask.

volatile probe fields (fixed). The static bools are now volatile.

After-hook registration coupling (no change). The RegisterAfterTestSessionHook omission is intentional and already documented in the XML comment on EnsureClassAndAssemblyHooksExecutedAsync. The hypothetical regression requires a new skip path inserted between the gate and ExecuteAsync that doesn't exist today; adding a guard for it now is speculative. Left as-is.

Comment on the duplicate GetOrCreateBeforeTestSessionTask call site (no change). The method's XML doc already states the matching awaits in ExecuteAsync are no-ops because the tasks are cached. An extra inline comment would be redundant.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: fix(engine): run lifecycle hooks before test class construction (#6192) — Follow-up

Previous Feedback Addressed

All critical and minor items from the prior two reviews have been resolved in commit c12d654:

Item Status
Missing ClassContext.RestoreExecutionContext() before constructor ✅ Fixed — moved to TestCoordinator immediately before CreateInstanceAsync on both paths
Test coverage: Before(Class)/Before(Assembly) not covered ✅ Fixed — Bug6192Tests now includes explicit [Before(Class)] and [Before(Assembly)] hooks
Retry path not tested ✅ Fixed — Bug6192RetryTests covers the ExecuteTestLifecycleAsync code path
EnsureTestSessionHooksExecutedAsync returns Task not ValueTask ✅ Fixed
Probe booleans missing volatile ✅ Fixed
After-hook registration coupling (intentional non-fix) ✅ Documented in XML comment — accepted

The author's explanation for the ClassContext.RestoreExecutionContext() placement is technically correct: restoring inside the async gate method doesn't persist because the ambient ExecutionContext is reset on return; it must live synchronously in the caller. The regression test (AsyncLocal asserting in the constructor) verifies this soundly.


What Looks Good

  • Correct execution context chain — Session → Assembly → Class restore calls in EnsureClassAndAssemblyHooksExecutedAsync, then Class restore in TestCoordinator before construction. Mirrors the ExecuteAsync chain exactly.
  • Idempotency is the right lever — pre-running the cached hook tasks before construction means ExecuteAsync's subsequent awaits are genuine no-ops, with no risk of hooks running twice.
  • Both code paths patched — no-retry fast path (line ~134) and retry path (ExecuteTestLifecycleAsync) both have the gate.
  • Comprehensive regression test — covers all four hook types, AsyncLocal propagation, and the retry path. The "throw in constructor" pattern is a reliable sentinel.
  • Cached factory delegates_beforeTestSessionHookFactory / _beforeAssemblyHookFactory avoid per-invocation closure allocations on the hot path.

Minor Observation (non-blocking)

GetOrCreateBeforeClassTask is passed _hookExecutor directly (no cached factory delegate), while the session and assembly equivalents use the pre-cached _beforeTestSessionHookFactory / _beforeAssemblyHookFactory. This is consistent with how it was already called in ExecuteAsync and likely doesn't allocate a closure (field reference), but the asymmetry is noticeable. Not worth changing now — noting for completeness.


Overall

All feedback has been addressed correctly. The fix is architecturally sound, minimal in scope, and well-tested. Happy to approve.

This was referenced Jun 22, 2026
atharvalade pushed a commit to apache/iggy that referenced this pull request Jun 23, 2026
Updated
[Microsoft.Extensions.Configuration](https://github.com/dotnet/dotnet)
from 10.0.8 to 10.0.9.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Configuration's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Configuration.Binder](https://github.com/dotnet/dotnet)
from 10.0.8 to 10.0.9.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Configuration.Binder's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Configuration.Json](https://github.com/dotnet/dotnet)
from 10.0.8 to 10.0.9.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Configuration.Json's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [Microsoft.Extensions.Logging](https://github.com/dotnet/dotnet)
from 10.0.8 to 10.0.9.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Logging's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/dotnet)
from 10.0.8 to 10.0.9.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Logging.Abstractions's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Logging.Console](https://github.com/dotnet/dotnet)
from 10.0.8 to 10.0.9.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Logging.Console's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [TUnit](https://github.com/thomhurst/TUnit) from 1.51.0 to
1.56.0.

<details>
<summary>Release notes</summary>

_Sourced from [TUnit's
releases](https://github.com/thomhurst/TUnit/releases)._

## 1.56.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.56.0 -->

## What's Changed
### Other Changes
* fix(aspnetcore): serialize WithWebHostBuilder to stop
_derivedFactories race (flaky disposal NRE) by @​thomhurst in
thomhurst/TUnit#6251
* fix(mocks): wrap a real object whose class has no parameterless ctor
(#​6253) by @​thomhurst in thomhurst/TUnit#6255
* fix(mocks): implement `new`-hidden base interface members in wrapper
(#​6252) by @​thomhurst in thomhurst/TUnit#6256
* fix(mocks): mocking a method with more params than Func/Action arity
(#​6254) by @​thomhurst in thomhurst/TUnit#6257
### Dependencies
* chore(deps): update tunit to 1.55.2 by @​thomhurst in
thomhurst/TUnit#6248
* chore(deps): update aspire to 13.4.4 by @​thomhurst in
thomhurst/TUnit#6249
* chore(deps): update dependency stackexchange.redis to v3 by
@​thomhurst in thomhurst/TUnit#6250


**Full Changelog**:
thomhurst/TUnit@v1.55.2...v1.56.0

## 1.55.2

<!-- Release notes generated using configuration in .github/release.yml
at v1.55.2 -->

## What's Changed
### Other Changes
* fix(aspire): publish TUnit.Aspire.Core package (#​6246) by @​thomhurst
in thomhurst/TUnit#6247
### Dependencies
* chore(deps): update tunit to 1.55.0 by @​thomhurst in
thomhurst/TUnit#6245


**Full Changelog**:
thomhurst/TUnit@v1.55.0...v1.55.2

## 1.55.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.55.0 -->

## What's Changed
### Other Changes
* feat(aspire): add TUnit.Aspire.Core without TUnit metapackage
dependency (#​5471) by @​thomhurst in
thomhurst/TUnit#6243
* fix(analyzers): scope TUnit0031 async-void rule to tests and hooks
(#​6190) by @​thomhurst in thomhurst/TUnit#6244
### Dependencies
* chore(deps): update dependency streamjsonrpc to 2.25.28 by @​thomhurst
in thomhurst/TUnit#6232
* chore(deps): update tunit to 1.54.0 by @​thomhurst in
thomhurst/TUnit#6233
* chore(deps): bump joi from 17.13.3 to 17.13.4 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6234
* chore(deps): update dependency polyfill to 10.9.0 by @​thomhurst in
thomhurst/TUnit#6238
* chore(deps): update _tunitpolyfillversion to 10.9.0 by @​thomhurst in
thomhurst/TUnit#6237
* chore(deps): update dependency polyfill to 10.10.0 by @​thomhurst in
thomhurst/TUnit#6242
* chore(deps): update _tunitpolyfillversion to 10.10.0 by @​thomhurst in
thomhurst/TUnit#6241


**Full Changelog**:
thomhurst/TUnit@v1.54.0...v1.55.0

## 1.54.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.54.0 -->

## What's Changed
### Other Changes
* Generate collection-shape drill-in overloads (#​6185) by @​thomhurst
in thomhurst/TUnit#6218
* feat(mocks): setup/verify on secondary interfaces of multi-type mocks
by @​thomhurst in thomhurst/TUnit#6230
* perf: reduce allocations in source-gen test building hot paths by
@​thomhurst in thomhurst/TUnit#6228
* perf: shrink generated TestEntry builder IL via shared TUnit.Core
factory helpers by @​thomhurst in
thomhurst/TUnit#6231
### Dependencies
* chore(deps): update tunit to 1.53.0 by @​thomhurst in
thomhurst/TUnit#6199
* chore(deps): update verify to 31.19.1 by @​thomhurst in
thomhurst/TUnit#6200
* chore(deps): update dependency messagepack to 3.1.7 by @​thomhurst in
thomhurst/TUnit#6203
* chore(deps): update dependency fsharp.core to 10.1.301 by @​thomhurst
in thomhurst/TUnit#6202
* chore(deps): update dependency microsoft.entityframeworkcore to 10.0.9
by @​thomhurst in thomhurst/TUnit#6205
* chore(deps): update dependency dotnet-sdk to v10.0.301 by @​thomhurst
in thomhurst/TUnit#6204
* chore(deps): update dependency microsoft.templateengine.authoring.cli
to v10.0.301 by @​thomhurst in
thomhurst/TUnit#6206
* chore(deps): update dependency
microsoft.templateengine.authoring.templateverifier to 10.0.301 by
@​thomhurst in thomhurst/TUnit#6207
* chore(deps): update microsoft.aspnetcore to 10.0.9 by @​thomhurst in
thomhurst/TUnit#6209
* chore(deps): update dependency system.commandline to 2.0.9 by
@​thomhurst in thomhurst/TUnit#6208
* chore(deps): update microsoft.extensions by @​thomhurst in
thomhurst/TUnit#6211
* chore(deps): update dependency dompurify to v3.4.9 by @​thomhurst in
thomhurst/TUnit#6213
* chore(deps): bump shell-quote from 1.8.3 to 1.8.4 in /docs by
@​dependabot[bot] in thomhurst/TUnit#6210
* chore(deps): update dependency polly to 8.7.0 by @​thomhurst in
thomhurst/TUnit#6214
* chore(deps): update dependency microsoft.net.stringtools to 18.7.1 by
@​thomhurst in thomhurst/TUnit#6215
* chore(deps): update microsoft.build to 18.7.1 by @​thomhurst in
thomhurst/TUnit#6216
* chore(deps): update opentelemetry to 1.16.0 by @​thomhurst in
thomhurst/TUnit#6217
* chore(deps): update dependency dompurify to v3.4.10 by @​thomhurst in
thomhurst/TUnit#6229


**Full Changelog**:
thomhurst/TUnit@v1.53.0...v1.54.0

## 1.53.0

<!-- Release notes generated using configuration in .github/release.yml
at v1.53.0 -->

## What's Changed
### Other Changes
* feat(assertions): return typed value from IsAssignableTo<T> (#​6184)
by @​thomhurst in thomhurst/TUnit#6187
* fix: stop doubling backslashes in source-gen emitted FilePath (breaks
HTML report source links) by @​thomhurst in
thomhurst/TUnit#6193
* feat(assertions): add ContainsKey().And.Value drill-in for
dictionaries (#​6185) by @​thomhurst in
thomhurst/TUnit#6188
* fix(tests): snapshot ExecutionLog under lock to fix parallel race by
@​thomhurst in thomhurst/TUnit#6194
* fix(engine): run lifecycle hooks before test class construction
(#​6192) by @​thomhurst in thomhurst/TUnit#6195
* feat(assertions): inference-friendly pinned overload for covariant
[AssertionExtension] with own generic (#​5922) by @​thomhurst in
thomhurst/TUnit#6196
* feat: add DeferEnumeration to defer data-source expansion to runtime
(#​5833) by @​thomhurst in thomhurst/TUnit#6197
### Dependencies
* chore(deps): update tunit to 1.51.0 by @​thomhurst in
thomhurst/TUnit#6186
* chore(deps): update microsoft.testing to 18.8.0 by @​thomhurst in
thomhurst/TUnit#6191
* chore(deps): update aspire to 13.4.3 by @​thomhurst in
thomhurst/TUnit#6198


**Full Changelog**:
thomhurst/TUnit@v1.51.0...v1.53.0

Commits viewable in [compare
view](thomhurst/TUnit@v1.51.0...v1.56.0).
</details>

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hubert Gruszecki <h.gruszecki@gmail.com>
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.

[Bug]: Test class constructors are called before 'BeforeAssembly' and 'BeforeClass' events

1 participant