Skip to content

Commit 1284bb8

Browse files
IT-VBFKIT-VBFKjnyrup
committed
Do not continue asserting on the concrete exception type when the exception is null (fluentassertions#2398)
* Improved the failure message for `ThrowExactly[Async]` * Add release notes Co-authored-by: Jonas Nyrup <[email protected]> --------- Co-authored-by: IT-VBFK <[email protected]> Co-authored-by: Jonas Nyrup <[email protected]>
1 parent 7299c58 commit 1284bb8

File tree

5 files changed

+51
-4
lines changed

5 files changed

+51
-4
lines changed

Src/FluentAssertions/Specialized/AsyncFunctionAssertions.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,15 @@ public async Task<ExceptionAssertions<TException>> ThrowExactlyAsync<TException>
138138
{
139139
Exception exception = await InvokeWithInterceptionAsync(Subject);
140140

141-
Execute.Assertion
141+
success = Execute.Assertion
142142
.ForCondition(exception is not null)
143143
.BecauseOf(because, becauseArgs)
144144
.FailWith("Expected {0}{reason}, but no exception was thrown.", expectedType);
145145

146-
exception.Should().BeOfType(expectedType, because, becauseArgs);
146+
if (success)
147+
{
148+
exception.Should().BeOfType(expectedType, because, becauseArgs);
149+
}
147150

148151
return new ExceptionAssertions<TException>(new[] { exception as TException });
149152
}

Src/FluentAssertions/Specialized/DelegateAssertions.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,15 @@ public ExceptionAssertions<TException> ThrowExactly<TException>(string because =
140140

141141
Type expectedType = typeof(TException);
142142

143-
Execute.Assertion
143+
success = Execute.Assertion
144144
.ForCondition(exception is not null)
145145
.BecauseOf(because, becauseArgs)
146146
.FailWith("Expected {0}{reason}, but no exception was thrown.", expectedType);
147147

148-
exception.Should().BeOfType(expectedType, because, becauseArgs);
148+
if (success)
149+
{
150+
exception.Should().BeOfType(expectedType, because, becauseArgs);
151+
}
149152

150153
return new ExceptionAssertions<TException>(new[] { exception as TException });
151154
}

Tests/FluentAssertions.Specs/Specialized/DelegateAssertionSpecs.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Threading.Tasks;
3+
using FluentAssertions.Execution;
24
using FluentAssertions.Specialized;
35
using Xunit;
46

@@ -34,4 +36,22 @@ public void When_injecting_a_null_clock_it_should_throw()
3436
act.Should().ThrowExactly<ArgumentNullException>()
3537
.WithParameterName("clock");
3638
}
39+
40+
public class ThrowExactly
41+
{
42+
[Fact]
43+
public void Does_not_continue_assertion_on_exact_exception_type()
44+
{
45+
// Arrange
46+
var a = () => { };
47+
48+
// Act
49+
using var scope = new AssertionScope();
50+
a.Should().ThrowExactly<InvalidOperationException>();
51+
52+
// Assert
53+
scope.Discard().Should().ContainSingle()
54+
.Which.Should().Match("*InvalidOperationException*no exception*");
55+
}
56+
}
3757
}

Tests/FluentAssertions.Specs/Specialized/TaskAssertionSpecs.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Threading.Tasks;
44
using FluentAssertions.Execution;
55
using FluentAssertions.Extensions;
6+
using FluentAssertions.Specialized;
67
using Xunit;
78
using Xunit.Sdk;
89

@@ -466,6 +467,24 @@ await action.Should().ThrowAsync<XunitException>().WithMessage(
466467
}
467468
}
468469

470+
public class ThrowExactlyAsync
471+
{
472+
[Fact]
473+
public async Task Does_not_continue_assertion_on_exact_exception_type()
474+
{
475+
// Arrange
476+
var a = () => Task.Delay(1);
477+
478+
// Act
479+
using var scope = new AssertionScope();
480+
await a.Should().ThrowExactlyAsync<InvalidOperationException>();
481+
482+
// Assert
483+
scope.Discard().Should().ContainSingle()
484+
.Which.Should().Match("*InvalidOperationException*no exception*");
485+
}
486+
}
487+
469488
[Collection("UIFacts")]
470489
public class CompleteWithinAsyncUIFacts
471490
{

docs/_pages/releases.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ sidebar:
2121
* Capitalize `true` and `false` in failure messages and make them formattable to a custom `BooleanFormatter` - [#2390](https://github.com/fluentassertions/fluentassertions/pull/2390), [#2393](https://github.com/fluentassertions/fluentassertions/pull/2393)
2222
* Improved the failure message for `NotBeOfType` when wrapped in an `AssertionScope` and the subject is null - [#2399](https://github.com/fluentassertions/fluentassertions/pull/2399)
2323
* Improved the failure message for `BeWritable`/`BeReadable` when wrapped in an `AssertionScope` and the subject is read-only/write-only - [#2399](https://github.com/fluentassertions/fluentassertions/pull/2399)
24+
* Improved the failure message for `ThrowExactly[Async]` when wrapped in an `AssertionScope` and no exception is thrown - [#2398](https://github.com/fluentassertions/fluentassertions/pull/2398)
25+
2426

2527
## 6.12.0
2628

0 commit comments

Comments
 (0)