Skip to content

Commit 59c8d4c

Browse files
authored
Merge pull request #1131 from Siemens-Healthineers/ExecutionHookAttribute_Doc_SetUpTearDown
Enhanced docu for Execution Hooks to show users how to distinguish be…
2 parents e0923a8 + ed334e7 commit 59c8d4c

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

docs/articles/nunit/extending-nunit/Execution-Hooks.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ Each hook receives a `HookData` instance:
4747

4848
Use these fields for logging, conditional logic, or adaptive cleanup.
4949

50+
## One-Time vs Per-Test Setup/TearDown
51+
52+
`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).
53+
54+
See [Example: One-Time vs Per-Test Setup and TearDown](#example-one-time-vs-per-test-setup-and-teardown) for a complete hook implementation.
55+
56+
## Example: One-Time vs Per-Test Setup and TearDown
57+
58+
[!code-csharp[ExecutionHookAttributeExample](~/snippets/Snippets.NUnit/ExecutionHookExamples.cs#OneTimeVsPerTestSetupTearDownExample)]
59+
5060
## Example: Measure Time for Setup
5161

5262
[!code-csharp[ExecutionHookAttributeExample](~/snippets/Snippets.NUnit/ExecutionHookExamples.cs#TimingHookAttribute)]

docs/snippets/Snippets.NUnit/ExecutionHookExamples.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,32 @@ public override void AfterEverySetUpHook(HookData hookData)
2222
if (_starts.TryGetValue(key, out var start))
2323
{
2424
var elapsed = DateTime.UtcNow - start;
25-
TestContext.WriteLine($"[Timing] " +
25+
TestContext.Progress.WriteLine($"[Timing] " +
2626
$"{hookData.Context.Test.MethodName} " +
2727
$"took {elapsed.TotalMilliseconds:F1} ms");
2828
}
2929
}
3030
}
3131
#endregion
3232

33+
#region OneTimeVsPerTestSetupTearDownExample
34+
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
35+
public sealed class OneTimeVsPerTestSetupTearDownHookAttribute : ExecutionHookAttribute
36+
{
37+
public override void BeforeEverySetUpHook(HookData data)
38+
{
39+
var scope = data.Context.Test.IsSuite ? "OneTimeSetUp" : "SetUp";
40+
TestContext.Progress.WriteLine($"{scope}: {data.HookedMethod?.Name}");
41+
}
42+
43+
public override void AfterEveryTearDownHook(HookData data)
44+
{
45+
var scope = data.Context.Test.IsSuite ? "OneTimeTearDown" : "TearDown";
46+
TestContext.Progress.WriteLine($"{scope}: {data.HookedMethod?.Name}");
47+
}
48+
}
49+
#endregion
50+
3351
#region Usage
3452
[TestFixture]
3553
[TimeMeasurementHook]
@@ -52,7 +70,7 @@ private void Log(string phase, HookData data, bool withException = false)
5270
var name = data.Context.Test.MethodName;
5371
var exInfo = withException && data.Exception != null ?
5472
$" (EX: {data.Exception.GetType().Name})" : string.Empty;
55-
TestContext.WriteLine($"[{phase}] {name}{exInfo}");
73+
TestContext.Progress.WriteLine($"[{phase}] {name}{exInfo}");
5674
}
5775

5876
public override void BeforeEverySetUpHook(HookData d)

0 commit comments

Comments
 (0)