FluentAssertions 异常断言技术详解

FluentAssertions 异常断言技术详解

fluentassertions A very extensive set of extension methods that allow you to more naturally specify the expected outcome of a TDD or BDD-style unit tests. Targets .NET Framework 4.7, as well as .NET Core 2.1, .NET Core 3.0, .NET 6, .NET Standard 2.0 and 2.1. Supports the unit test frameworks MSTest2, NUnit3, XUnit2, MSpec, and NSpec3. fluentassertions 项目地址: https://gitcode.com/gh_mirrors/fl/fluentassertions

引言

在单元测试中,异常处理是一个非常重要的环节。FluentAssertions 提供了一套优雅且强大的异常断言机制,让开发者能够以流畅的方式验证代码是否按预期抛出异常。本文将全面介绍 FluentAssertions 中的异常断言功能。

基本异常断言

验证方法抛出特定异常

最基本的异常断言是验证某个方法是否抛出了特定类型的异常:

subject.Invoking(y => y.Foo("Hello"))
    .Should().Throw<InvalidOperationException>()
    .WithMessage("Hello is not allowed at this moment");

这段代码验证了 Foo 方法在被调用时会抛出 InvalidOperationException,并且异常消息包含特定内容。

使用 Arrange-Act-Assert 模式

对于偏好 AAA 模式的开发者,可以使用以下方式:

Action act = () => subject.Foo2("Hello");

act.Should().Throw<InvalidOperationException>()
    .WithInnerException<ArgumentException>()
    .WithMessage("whatever");

这种方式不仅验证了异常类型,还验证了内部异常和消息内容。

高级异常验证

验证异常属性

FluentAssertions 允许对异常实例的属性进行详细验证:

var act = () => subject.Foo(null);

act.Should().Throw<ArgumentNullException>()
    .WithParameterName("message");

使用 Where 进行自定义验证

对于更复杂的验证场景,可以使用 Where 方法:

var act = () => subject.Foo(null);
act.Should().Throw<ArgumentNullException>()
   .Where(e => e.Message.StartsWith("did"));

通配符匹配异常消息

FluentAssertions 支持使用通配符匹配异常消息:

var act = () => subject.Foo(null);
act.Should().Throw<ArgumentNullException>()
   .WithMessage("?did*");

支持的通配符包括:

  • *:匹配零个或多个字符
  • ?:匹配一个字符

验证不抛出异常

基本不抛出异常验证

var act = () => subject.Foo("Hello");
act.Should().NotThrow();

验证不抛出特定异常

var act = () => subject.Foo("Hello");
act.Should().NotThrow<InvalidOperationException>();

延迟验证

对于需要等待一段时间才能确定结果的场景:

var act = () => service.IsReady().Should().BeTrue();
act.Should().NotThrowAfter(10.Seconds(), 100.Milliseconds());

第二个参数指定了重试间隔时间。

处理 yield 返回的方法

对于使用 yield 返回集合的方法,需要使用 Enumerating 强制枚举:

Func<IEnumerable<char>> func = () => obj.SomeMethodThatUsesYield("blah");
func.Enumerating().Should().Throw<ArgumentException>();

或者:

obj.Enumerating(x => x.SomeMethodThatUsesYield("blah")).Should().Throw<ArgumentException>();

精确异常匹配

使用 ThrowExactlyWithInnerExceptionExactly 可以精确匹配异常类型:

// 会失败,如果抛出的是 ApplicationException 而不是 Exception
act.Should().ThrowExactly<Exception>(); 

异步异常处理

基本异步异常验证

var act = () => asyncObject.ThrowAsync<ArgumentException>();
await act.Should().ThrowAsync<InvalidOperationException>();
await act.Should().NotThrowAsync();

使用 Awaiting 方法

var act = asyncObject.Awaiting(x => x.ThrowAsync<ArgumentException>());
await act.Should().ThrowAsync<ArgumentException>();

异步延迟验证

await act.Should().NotThrowAfterAsync(2.Seconds(), 100.Milliseconds());

简化语法

使用 FluentActions 可以进一步简化代码:

FluentActions.Invoking(() => MyClass.Create(null))
    .Should().Throw<ArgumentNullException>();

或者使用静态导入:

using static FluentAssertions.FluentActions;

Invoking(() => MyClass.Create(null))
    .Should().Throw<ArgumentNullException>();

处理 AggregateException

FluentAssertions 会自动解包 AggregateException,使得断言可以正常工作:

// 即使异常被包装在 AggregateException 中,也能正常工作
act.Should().Throw<InvalidOperationException>(); 

ThrowExactly 不会自动解包,它要求异常必须精确匹配。

总结

FluentAssertions 提供了全面而强大的异常断言功能,无论是同步还是异步代码,都能以流畅的方式进行验证。通过本文介绍的各种方法,开发者可以编写出更清晰、更健壮的单元测试代码。

fluentassertions A very extensive set of extension methods that allow you to more naturally specify the expected outcome of a TDD or BDD-style unit tests. Targets .NET Framework 4.7, as well as .NET Core 2.1, .NET Core 3.0, .NET 6, .NET Standard 2.0 and 2.1. Supports the unit test frameworks MSTest2, NUnit3, XUnit2, MSpec, and NSpec3. fluentassertions 项目地址: https://gitcode.com/gh_mirrors/fl/fluentassertions

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

余媛奕Lowell

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值