docs/articles/nunit/extending-nunit/Execution-Hooks.md
Added in NUnit 4.5
Execution Hooks provide structured, ordered, exception-aware extension points around each core test lifecycle phase. They complement (and can wrap) Action Attributes while staying focused on execution.
Key differences to Action Attributes:
Execution Hooks should be used when there is a need to:
Derive from ExecutionHookAttribute and override only the methods that are relevant:
| Method | Triggered immediately | Applies To |
|---|---|---|
BeforeEverySetUpHook | Before each [SetUp] or [OneTimeSetUp] method | All fixture & base fixture setup methods |
AfterEverySetUpHook | After each [SetUp] or [OneTimeSetUp] method | All fixture & base fixture setup methods |
BeforeTestHook | Before the test method | The test method |
AfterTestHook | After the test method | The test method |
BeforeEveryTearDownHook | Before each [TearDown] or [OneTimeTearDown] method | All fixture & base fixture teardown methods |
AfterEveryTearDownHook | After each [TearDown] or [OneTimeTearDown] method | All fixture & base fixture teardown methods |
BeforeTestActionBeforeTestHook | Before an ITestAction.BeforeTest(ITest) executes | Each applicable Action Attribute |
BeforeTestActionAfterTestHook | After an ITestAction.BeforeTest(ITest) executes | Each applicable Action Attribute |
AfterTestActionBeforeTestHook | Before an ITestAction.AfterTest(ITest) executes | Each applicable Action Attribute |
AfterTestActionAfterTestHook | After an ITestAction.AfterTest(ITest) executes | Each applicable Action Attribute |
This derived attribute can be applied at the method, class, or assembly level.
Each hook receives a HookData instance:
Context: A TestContext snapshot (current test, properties, etc.).HookedMethod: The MethodInfoAdapter of the method currently executing (e.g., the specific [SetUp], test, or [TearDown]).Exception: Non-null only for after-hooks when the hooked method threw.Use these fields for logging, conditional logic, or adaptive cleanup.
BeforeEverySetUpHook/AfterEverySetUpHook and BeforeEveryTearDownHook/AfterEveryTearDownHook run for both per-test and one-time setup/teardown. Inside a hook, the supported way to distinguish the two is the current test context: Context.Test.IsSuite is true for [OneTimeSetUp]/[OneTimeTearDown] (suite context) and false for [SetUp]/[TearDown] (test method context).
See Example: One-Time vs Per-Test Setup and TearDown for a complete hook implementation.
[!code-csharpExecutionHookAttributeExample]
[!code-csharpExecutionHookAttributeExample]
Usage:
[!code-csharpExecutionHookAttributeExample]
[!code-csharpExecutionHookAttributeExample]
In general:
HookData.Behavior illustrated by hooking a test method:
BeforeTestHook throws, the test method body is skipped, but its AfterTestHook still runs (with HookData.Exception set) allowing cleanup/logging.AfterTestHook throws, NUnit still proceeds with TearDown phases (remaining hooks and teardown methods run).AfterTestHook executions.HookData.Exception populated.If multiple attributes are applied:
BeforeEverySetUpHook, BeforeTestHook, etc.) execute in the order, attributes were applied (declaration order on the method/class/assembly).Because the AttributeUsage targets can be chosen on the derived attribute, control over where hooks can be applied is provided:
Hooks from broader scopes wrap those from narrower scopes. For a single test method with an assembly-level and a method-level TimingHook:
BeforeTestHook runs first.BeforeTestHook runs.AfterTestHook runs.AfterTestHook runs.