Skip to content

Commit c7e915b

Browse files
authored
Rework assert.multiple behavior under debugger to throw on each failure (nunit#4749)
* rework assert.multiple behavior under debugger to throw on each failure * address CR * copy ThrowOnEachFailureUnderDebugger to child context
1 parent 285bfa5 commit c7e915b

File tree

5 files changed

+28
-14
lines changed

5 files changed

+28
-14
lines changed

src/NUnitFramework/framework/Api/FrameworkPackageSettings.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ public static class FrameworkPackageSettings
8888
public const string StopOnError = "StopOnError";
8989

9090
/// <summary>
91-
/// If true, asserts in multiple asserts block will throw immediately.
91+
/// If true, asserts in multiple asserts block will throw first-chance exception on failure.
9292
/// </summary>
93-
public const string DisableMultipleAssertsUnderDebugger = "DisableMultipleAssertsUnderDebugger";
93+
public const string ThrowOnEachFailureUnderDebugger = "ThrowOnEachFailureUnderDebugger";
9494

9595
/// <summary>
9696
/// If true, use of the event queue is suppressed and test events are synchronous.

src/NUnitFramework/framework/Api/NUnitTestAssemblyRunner.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ private TestExecutionContext CreateTestExecutionContext(ITest loadedTest, ITestL
317317
context.CurrentUICulture = new CultureInfo((string)uiCulture, false);
318318
if (Settings.TryGetValue(FrameworkPackageSettings.StopOnError, out var stopOnError))
319319
context.StopOnError = (bool)stopOnError;
320-
if (Settings.TryGetValue(FrameworkPackageSettings.DisableMultipleAssertsUnderDebugger, out var disableMultiple))
321-
context.DisableMultipleAssertsUnderDebugger = (bool)disableMultiple;
320+
if (Settings.TryGetValue(FrameworkPackageSettings.ThrowOnEachFailureUnderDebugger, out var throwOnEachFailure))
321+
context.ThrowOnEachFailureUnderDebugger = (bool)throwOnEachFailure;
322322

323323
// Apply attributes to the context
324324

src/NUnitFramework/framework/Assert.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,9 +320,22 @@ private static void ReportFailure(string message)
320320
result.RecordAssertion(AssertionStatus.Failed, message, GetStackTrace());
321321
result.RecordTestCompletion();
322322

323-
// If we are outside any multiple assert block or multiple asserts disabled, then throw
324-
if (TestExecutionContext.CurrentContext.MultipleAssertLevel == 0 || (TestExecutionContext.CurrentContext.DisableMultipleAssertsUnderDebugger && Debugger.IsAttached))
323+
// If multiple asserts disabled, then throw
324+
if (TestExecutionContext.CurrentContext.MultipleAssertLevel == 0)
325+
{
325326
throw new AssertionException(result.Message);
327+
}
328+
else if (TestExecutionContext.CurrentContext.ThrowOnEachFailureUnderDebugger && Debugger.IsAttached)
329+
{
330+
try
331+
{
332+
throw new AssertionException(result.Message);
333+
}
334+
catch (AssertionException)
335+
{
336+
// we catch exception for multiple assert block to not change observed behavior but still allow user to break into debugger
337+
}
338+
}
326339
}
327340

328341
private static void IssueWarning(string message)

src/NUnitFramework/framework/Internal/TestExecutionContext.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public TestExecutionContext(TestExecutionContext other)
108108
_listener = other._listener;
109109
StopOnError = other.StopOnError;
110110
TestCaseTimeout = other.TestCaseTimeout;
111+
ThrowOnEachFailureUnderDebugger = other.ThrowOnEachFailureUnderDebugger;
111112
UseCancellation = other.UseCancellation;
112113
CancellationToken = other.CancellationToken;
113114
UpstreamActions = new List<ITestAction>(other.UpstreamActions);
@@ -314,9 +315,9 @@ public Randomizer RandomGenerator
314315
internal int MultipleAssertLevel { get; set; }
315316

316317
/// <summary>
317-
/// Gets or sets wether asserts in multiple assert block should throw immediately under debugger.
318+
/// Gets or sets wether asserts in multiple assert block should throw first-change exceptions under debugger.
318319
/// </summary>
319-
internal bool DisableMultipleAssertsUnderDebugger { get; set; }
320+
internal bool ThrowOnEachFailureUnderDebugger { get; set; }
320321

321322
/// <summary>
322323
/// Gets or sets the test case timeout value

src/NUnitFramework/tests/Internal/TestExecutionContextTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -660,18 +660,18 @@ public async Task CanAccessTestCaseTimeout_Async()
660660
[Test]
661661
public void CanAccessDisableMultipleAssertsUnderDebugger()
662662
{
663-
var value = _fixtureContext.DisableMultipleAssertsUnderDebugger;
664-
Assert.That(_setupContext.DisableMultipleAssertsUnderDebugger, Is.EqualTo(value));
665-
Assert.That(TestExecutionContext.CurrentContext.DisableMultipleAssertsUnderDebugger, Is.EqualTo(value));
663+
var value = _fixtureContext.ThrowOnEachFailureUnderDebugger;
664+
Assert.That(_setupContext.ThrowOnEachFailureUnderDebugger, Is.EqualTo(value));
665+
Assert.That(TestExecutionContext.CurrentContext.ThrowOnEachFailureUnderDebugger, Is.EqualTo(value));
666666
}
667667

668668
[Test]
669669
public async Task CanAccessDisableMultipleAssertsUnderDebugger_Async()
670670
{
671-
var value = TestExecutionContext.CurrentContext.DisableMultipleAssertsUnderDebugger;
672-
Assert.That(value, Is.EqualTo(_setupContext.DisableMultipleAssertsUnderDebugger));
671+
var value = TestExecutionContext.CurrentContext.ThrowOnEachFailureUnderDebugger;
672+
Assert.That(value, Is.EqualTo(_setupContext.ThrowOnEachFailureUnderDebugger));
673673
await YieldAsync();
674-
Assert.That(TestExecutionContext.CurrentContext.DisableMultipleAssertsUnderDebugger, Is.EqualTo(value));
674+
Assert.That(TestExecutionContext.CurrentContext.ThrowOnEachFailureUnderDebugger, Is.EqualTo(value));
675675
}
676676

677677
#endregion

0 commit comments

Comments
 (0)