-
Notifications
You must be signed in to change notification settings - Fork 292
Add Assert.Scope() for soft assertions
#7355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
19a1f23
312a4a4
d860b27
b0208b3
6133a25
63dceb7
12d69af
f9133c3
61f218e
888a8a6
c68b24e
ceb625b
61899b1
bb40e99
328b1fb
e84eadc
b9d6aff
bc227a8
13ccc3b
c462a15
086a072
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
|
||
| namespace Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
|
||
| /// <summary> | ||
| /// A collection of helper classes to test various conditions within | ||
| /// unit tests. If the condition being tested is not met, an exception | ||
| /// is thrown. | ||
| /// </summary> | ||
| public sealed partial class Assert | ||
| { | ||
| /// <summary> | ||
| /// Creates a new assertion scope that collects assertion failures instead of throwing them immediately. | ||
| /// When the returned scope is disposed, all collected failures are thrown as a single <see cref="AssertFailedException"/>. | ||
| /// </summary> | ||
| /// <returns>An <see cref="IDisposable"/> representing the assertion scope.</returns> | ||
| /// <example> | ||
| /// <code> | ||
| /// using (Assert.Scope()) | ||
| /// { | ||
| /// Assert.AreEqual(1, 2); // collected, not thrown | ||
| /// Assert.IsTrue(false); // collected, not thrown | ||
| /// } | ||
| /// // AssertFailedException is thrown here with all collected failures. | ||
| /// </code> | ||
| /// </example> | ||
| public static IDisposable Scope() => new AssertScope(); | ||
|
Check failure on line 28 in src/TestFramework/TestFramework/Assertions/Assert.Scope.cs
|
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -37,8 +37,19 @@ private Assert() | |||||||||||||||||||||
| [DoesNotReturn] | ||||||||||||||||||||||
| [StackTraceHidden] | ||||||||||||||||||||||
| internal static void ThrowAssertFailed(string assertionName, string? message) | ||||||||||||||||||||||
Evangelink marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
| => throw new AssertFailedException( | ||||||||||||||||||||||
| string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AssertionFailed, assertionName, message)); | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| var assertionFailedException = new AssertFailedException(string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AssertionFailed, assertionName, message)); | ||||||||||||||||||||||
Evangelink marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||
| AssertScope? scope = AssertScope.Current; | ||||||||||||||||||||||
| if (scope is not null) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
|
||||||||||||||||||||||
| { | |
| { | |
| try | |
| { | |
| throw assertionFailedException; | |
| } | |
| catch (AssertFailedException ex) | |
| { | |
| assertionFailedException = ex; | |
| } |
Evangelink marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
|
||
| namespace Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
|
||
| /// <summary> | ||
| /// Represents a scope in which assertion failures are collected instead of thrown immediately. | ||
| /// When the scope is disposed, all collected failures are thrown as a single <see cref="AssertFailedException"/>. | ||
| /// </summary> | ||
| internal sealed class AssertScope : IDisposable | ||
| { | ||
| private static readonly AsyncLocal<AssertScope?> CurrentScope = new(); | ||
|
|
||
| private readonly List<AssertFailedException> _errors = []; | ||
Evangelink marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| private readonly AssertScope? _previousScope; | ||
| private bool _disposed; | ||
|
|
||
| internal AssertScope() | ||
| { | ||
| _previousScope = CurrentScope.Value; | ||
Evangelink marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| CurrentScope.Value = this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the current active <see cref="AssertScope"/>, or <see langword="null"/> if no scope is active. | ||
| /// </summary> | ||
| internal static AssertScope? Current => CurrentScope.Value; | ||
|
|
||
| /// <summary> | ||
| /// Adds an assertion failure message to the current scope. | ||
| /// </summary> | ||
| /// <param name="error">The assertion failure message.</param> | ||
| internal void AddError(AssertFailedException error) => _errors.Add(error); | ||
Evangelink marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// <inheritdoc/> | ||
| public void Dispose() | ||
| { | ||
| if (_disposed) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| _disposed = true; | ||
| CurrentScope.Value = _previousScope; | ||
|
|
||
| if (_errors.Count > 0) | ||
Evangelink marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| throw new AssertFailedException( | ||
| string.Format(CultureInfo.CurrentCulture, FrameworkMessages.AssertScopeFailure, _errors.Count), | ||
| new AggregateException(_errors)); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.