如何在单个测试中同时执行多个断言

前言

虽然,推荐做法是每次测试只断言一件事,但是,在实际工作中,我们可能需要对同一个对象同时执行多个断言。

例如,微软官方示例项目eShopOnContainers有一个测试用例的实现代码如下:

[Fact]
public async Task Add_to_cart_success()
{//Arrangevar fakeCatalogItem = GetFakeCatalogItem();_basketServiceMock.Setup(x => x.AddItemToBasket(It.IsAny<ApplicationUser>(), It.IsAny<Int32>())).Returns(Task.FromResult(1));//Actvar orderController = new CartController(_basketServiceMock.Object, _catalogServiceMock.Object, _identityParserMock.Object);orderController.ControllerContext.HttpContext = _contextMock.Object;var actionResult = await orderController.AddToCart(fakeCatalogItem);//AssertAssert.Equal("Catalog", redirectToActionResult.ControllerName);Assert.Equal("Index", redirectToActionResult.ActionName);
}

如果我们将所有断言都改成必定失败:

//Assert
Assert.Equal("WrongCatalog", redirectToActionResult.ControllerName);
Assert.Equal("WrongIndex", redirectToActionResult.ActionName);

但运行测试时,只会提示第一个失败的断言:

70767309db00afc6a01cd950d0017030.png

在这种情况下,一个个断言去验证并修正比较耗时。

如果同时能够看到所有失败的断言则更加有帮助。

手工实现

查看`Assert.Equal`的实现代码[1],它是通过抛出EqualException异常来表明断言失败:

public static void Equal<T>(T expected, T actual, IEqualityComparer<T> comparer)
{GuardArgumentNotNull(nameof(comparer), comparer);var expectedAsIEnum = expected as IEnumerable;var actualAsIEnum = actual as IEnumerable;// If both are IEnumerable (or null), see if we got an AssertEqualityComparer<T>, so that// we can invoke it to get the mismatched index.if ((expectedAsIEnum != null && (actual == null || actualAsIEnum != null)) ||(actualAsIEnum != null && expected == null)){var aec = comparer as AssertEqualityComparer<T>;int? mismatchedIndex;if (aec != null && !aec.Equals(expected, actual, out mismatchedIndex)){if (mismatchedIndex.HasValue)throw EqualException.FromEnumerable(expectedAsIEnum, actualAsIEnum, mismatchedIndex.Value);elsethrow new EqualException(expected, actual);}}if (!comparer.Equals(expected, actual))throw new EqualException(expected, actual);
}

而所有断言异常都继承自基类XunitException

89b3bacad82d4b4949db8f645f5f23b2.png

74c815aa5aa137fe83890c7080be8b99.png

因此,我们可以捕获每个断言的异常,然后将多个异常添加到集合中,在测试结束时再抛出:

var xunitExceptions = new List<XunitException>();
try
{Assert.Equal("WrongCatalog", redirectToActionResult.ControllerName);
}
catch (XunitException ex)
{xunitExceptions.Add(ex);
}try
{Assert.Equal("WrongIndex", redirectToActionResult.ActionName);
}
catch (XunitException ex)
{xunitExceptions.Add(ex);
}if (xunitExceptions.Any())
{throw new AggregateException(xunitExceptions.ToArray());
}

7124bcb9edfbf35043d3c9f77529b3ba.png

这里虽然列出了所有失败断言,但是所有错误显示了2遍,而且我们必须为测试编写大量的try-catch代码。

有不有更好的方法呢?!

FluentAssertions

FluentAssertions是一组.NET扩展方法,允许用更自然的语法去验证断言。

引用Nuget包FluentAssertions,示例的断言可以修改成如下格式:

redirectToActionResult.ControllerName.Should().Be("WrongCatalog");
redirectToActionResult.ActionName.Should().Be("WrongIndex");

除此之外,还可以将多个断言放到一个AssertionScope中,以便FluentAssertions在所有失败的范围末尾抛出一个异常:

using (new FluentAssertions.Execution.AssertionScope())
{redirectToActionResult.ControllerName.Should().Be("WrongCatalog");redirectToActionResult.ActionName.Should().Be("WrongIndex");
}

b0bf3d0f7bb8dabde37e1c933dbd20a4.png

结论

有时,将多个断言组合在一起测试是有意义的。

在这种情况下,可以使用FluentAssertions的AssertionScope来编写此类测试。

如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“

参考资料

[1]

Assert.Equal的实现代码: https://github.com/xunit/assert.xunit/blob/main/EqualityAsserts.cs#L78

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jquery如何获取元素的滚动高度

获取浏览器显示区域&#xff08;可视区域&#xff09;的高度 &#xff1a; $(window).height(); 获取浏览器显示区域&#xff08;可视区域&#xff09;的宽度 &#xff1a; $(window).width(); 获取页面的文档高度 $(document).height(); 获取页面的文档宽度 &a…

TCP/IP模型的各层的作用

第一种总结&#xff1a; TCP/IP模型&#xff1a;以无缝方式实现各种网络之间互连的网络体系结构。 TCP/IP模型共分四层&#xff0c;分别为应用层、传输层、互联网层和主机到网络层。 各层实现特定的功能&#xff0c;提供特定的服务和访问接口&#xff0c;并具有相对的独立性。 …

JAVA解决山脉数组的峰顶索引问题

JAVA解决山脉数组的峰顶索引问题 01 题目 符合下列属性的数组 arr 称为 山峰数组&#xff08;山脉数组&#xff09; &#xff1a; arr.length > 3 存在 i&#xff08;0 < i < arr.length - 1&#xff09;使得&#xff1a;arr[0] < arr[1] < ... arr[i-1] <…

php设计模式之单例(多例),注册器,观察者模式

单例(Singleton)模式和不常见的多例(Multiton)模式控制着应用程序中类的数量。如模式名称&#xff0c;单例只能实例化一次&#xff0c;只有一个对象&#xff0c;多例模式可以多次实例化。 基于Singleton的特性&#xff0c;我们经常用Singleton配置应用程序并定义应用程序中可能…

Oracle小知识总结

1. 每天的8&#xff1a;00到23&#xff1a;00每隔5分钟执行一个sql语句的JOB --建立一个存储过程 CREATE OR REPLACE PROCEDURE p_jobtest IS v_hh VARCHAR2(2); BEGIN v_hh : to_char(SYSDATE, hh24); IF v_hh > 08 AND v_hh < 22 THEN --你的sql语句 NULL; END IF; EN…

使用ArcGIS Server发布我们的数据

原文:使用ArcGIS Server发布我们的数据引言 上一篇我们已经安装好了ArcGIS体系的服务软件&#xff0c;这一篇将介绍如何把我们自己的数据通过ArcGIS Server发布出去&#xff0c;并且能够通过Web页面进行显示和编辑。 发布数据服务 在进行WebGIS开发中&#xff0c;地图显示的内容…

网关的一些知识

什么是网关 &#xff1a; 顾名思义&#xff0c;网关&#xff08;Gateway&#xff09;就是一个网络连接到另一个网络的“关口”。 种类&#xff1a; 按照不同的分类标准&#xff0c;网关也有很多种。TCP/IP协议里的网关是最常用的&#xff0c;在这里我们所讲的“网关”均指TCP/…

ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue, RingBuffer

1. ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue ArrayBlockingQueue, LinkedBlockingQueue 继承自 BlockingQueue, 他们的特点就是 Blocking, Blocking 特有的方法就是 take() 和 put(), 这两个方法是阻塞方法, 每当队列容量满的时候, put() 方法就会进入…

ASP.NET Core 中是否有 PostAsJsonAsync() 方法?

咨询区 LP13在 Asp.NET 中我一般都用 PostAsJsonAsync() 做数据提交&#xff0c;在 Asp.NET Core 时代我貌似没有找到&#xff0c;按照程序集的命名规范&#xff0c;我觉得应该也是由 Microsoft.AspNet.WebApi.Client 迁移到 Microsoft.AspNetCore.WebApi.Client 中。回答区 Je…

OSI七层模型的作用

第七层&#xff1a;应用层 数据 用户接口&#xff0c;提供用户程序“接口”。 第六层&#xff1a;表示层 数据 数据的表现形式&#xff0c;特定功能的实现&#xff0c;如数据加密。 第五层&#xff1a;会话层 数据 允许不同机器上的用户之间建立会话关系&#xff0c;如WINDOW…

MyBatis学习总结(17)——Mybatis分页插件PageHelper

2019独角兽企业重金招聘Python工程师标准>>> 如果你也在用Mybatis&#xff0c;建议尝试该分页插件&#xff0c;这一定是最方便使用的分页插件。 分页插件支持任何复杂的单表、多表分页&#xff0c;部分特殊情况请看重要提示。 想要使用分页插件&#xff1f;请看如何…

微信发力了,一键部署网站后端!

大家好&#xff0c;我是鱼皮。还记得么&#xff1f;之前我全程直播带大家从 0 到 1 做了一个包含前端、后端的 表情包网站项目 &#xff0c;支持搜索表情、自由裁切下载、给表情包配字等功能。爸爸表情包网站在线编辑下载但由于各方面的原因&#xff0c;我暂时将该网站战术下线…

数据可视化(9)--数据可视化6步法

在当前互联网&#xff0c;各种数据可视化图表层出不穷&#xff0c;本文尝试对数据可视化的方法进行归纳&#xff0c;整理成6步法。一般的数据图表都可以拆分成最基本的两类元素: 所描述的事物及这个事物的数值&#xff0c;我们暂且将其分别定义为指标和指标值。比如一个性别分布…

数据挖掘在呼叫中心的六大应用点

当前商业正在从“以产品为中心”到“以用户为中心”转变&#xff0c;很多企业将CRM作为企业成功的一个关键因素&#xff0c;呼叫中心作为影响用户最直接的渠道&#xff0c;起着至关重要的作用&#xff1b;利用数据挖掘技术&#xff0c;可以提高企业呼叫中心的效率的同时来增加客…

c++win32项目 如何显示后再删除一个绘图_iMATLAB 绘图扩展函数系列 | 让你绘图更自由(进阶专辑开篇)!...

本专辑参考了mathworks公司主页文件交换站的一些分享文件&#xff0c;遴选部分绘图扩展函数供初学者参考&#xff0c;仅用作学习资料传播&#xff0c;版权属于原作者&#xff0c;特此致谢。如有不妥&#xff0c;请联系删除。本专辑将持续更新&#xff0c;欢迎读者投稿自己绘图函…

HTML5:理解head

2019独角兽企业重金招聘Python工程师标准>>> HTML文档的head部分&#xff0c;通常包括指定页面标题&#xff0c;为搜索引擎提供关于页面本身的信息&#xff0c;加载样式表&#xff0c;以及加载JavaScript文件&#xff08;出于性能考虑&#xff0c;多数时候放在页面底…

Android之什么场景该使用单例模式总结

1、什么是单例模式 单例模式意味着只有一个对象,至于单例模式如何实现就不这里就不多说了,有很多种实现办法。 2、什么时候该使用单例模式?如果不使用单例模式会出现什么问题? 先举2个例子 例子1 当我们做得到最新的短信和最新的通话记录的时候,我们一般采…