ASP.NET Core 中做集成测试的三种方案

学习·进步

老张的哲学

不定期更新的

日常

  在平时的开发中,我们很少会关注到测试的问题,更别说集成测试了,除非是公司有硬性要求或者是自己的开源项目中,为了整体架构的完整性,需要用测试来做辅助点缀,而更多的也仅仅是单元测试(说的就是我自己????),最近在写书的时候才进一步考虑到这一点,如何在一个ASP.NET Core框架中,引入集成测试呢?

  这里我结合这三年开源的经验,总结了一些心得,给大家分享一下,如果有更好的建议,欢迎在评论区进行留言哟。

PS:单元测试就不说了,比较简单,最多就是依赖注入和MOCK的问题,不会的话也可以留言。

方案一:万物皆可Mock

  在软件测试当中,我们经常,甚至是到处都会用到mock来处理对象实例化的问题,在单元测试中,mock十分常见,毕竟是为了测试一个小模块,其他的就不需要考虑,直接mock就行了,如果在集成测试的时候,如何测试接口呢,比如BlogController如何使用?我在blog.core项目中,就是这么使用到的,示例代码如下:

 Mock<IBlogArticleServices> mockBlogSev = new Mock<IBlogArticleServices>();Mock<ILogger<BlogController>> mockLogger = new Mock<ILogger<BlogController>>();BlogController blogController;private IBlogArticleServices blogArticleServices;DI_Test dI_Test = new DI_Test();public BlogController_Should(){mockBlogSev.Setup(r => r.Query());var container = dI_Test.DICollections();blogArticleServices = container.Resolve<IBlogArticleServices>();blogController = new BlogController(mockLogger.Object);}

  说句实话,这并非是集成测试,这种写法可能比较低端,通过mock配合new,创建了控制器,然后调用接口,看起来不是很高大上,而且集成测试本来就是要测试整体性,不能把所有的参数都mock吧。同时官方好像也说过,不要到处使用mock。

而且,这种方案,也要考虑如何使用依赖注入的问题!

所以这种方案做集成测试我给:
⭐⭐

方案二:实例化TestServer对象

  这种是比较常见的,也是微软官方架构项目eShopOnContainers的推荐方案,简单来说,就是微软提供了一个TestSever的类,为我们提供一个类似WebHost的宿主服务器,只不过是测试服务器,那如何测试Controller控制器呢,示例代码如下:

 public TestServer CreateServer(){var path = Assembly.GetAssembly(typeof(CatalogScenariosBase)).Location;var hostBuilder = new WebHostBuilder().UseContentRoot(Path.GetDirectoryName(path)).ConfigureAppConfiguration(cb =>{cb.AddJsonFile("appsettings.json", optional: false).AddEnvironmentVariables();}).UseStartup<Startup>();var testServer = new TestServer(hostBuilder);testServer.Host.MigrateDbContext<CatalogContext>((context, services) =>{var env = services.GetService<IWebHostEnvironment>();var settings = services.GetService<IOptions<CatalogSettings>>();var logger = services.GetService<ILogger<CatalogContextSeed>>();new CatalogContextSeed().SeedAsync(context, env, settings, logger).Wait();}).MigrateDbContext<IntegrationEventLogContext>((_, __) => { });return testServer;}

  可以看到,通过new TestServer()的方式,生成一个服务器,就可以发起请求了,核心的还是我们的WebHostBuilder。

至于如何调用就更简单了,直接对server发起HttpClient请求即可:

  using (var server = CreateServer()){var response = await server.CreateClient().GetAsync(Get.ItemById(1));response.EnsureSuccessStatusCode();}


  这种是很简单的,而且也不用考虑mock的问题,毕竟用的直接就是web项目的WebHost宿主机Builder来构建的。

  但是有一个很致命的问题,我们在.NET5以后,使用Autofac做依赖注入的容器,而且ConfigureServices也是没有返回值的,这样在使用上面的TestServer,就会报错,提示找不到Autofac服务。

  但是如果你查看eShopOnContainers的源码后,就知道他们还是将ConfigureServices做了返回值处理:

 public IServiceProvider ConfigureServices(IServiceCollection servic{// 自定义服务扩展services.AddAppInsight(Configuration)// and so on....AddCustomMVC(Configuration);// 使用Autofac依赖注入容器var container = new ContainerBuilder();container.Populate(services);return new AutofacServiceProvider(container.Build());}

  如果你能接受这种依赖注入的方式的话,也是可以使用这种方案的,这是一个注意点,要知道。

所以这种方案做集成测试我给:
⭐⭐⭐⭐

方案三:使用.UseTestServer()

  除了上面的这种方式,还有一种方式,也是官方提供的,比较类似,也是通过创建宿主机服务器的形式,不过是新的HostBuilder的ConfigureWebHostDefaults方式创建的,示例代码如下:

public static IHostBuilder GetTestHost()
{return new HostBuilder()//替换autofac作为DI容器.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseTestServer().UseStartup<Startup>();}).ConfigureAppConfiguration((host, builder) =>{builder.SetBasePath(Directory.GetCurrentDirectory());builder.AddJsonFile("appsettings.json", optional: true);builder.AddEnvironmentVariables();});
}

  既然上面说了我们不能单独处理自定义容器,我们就和之前一样,指定就好,设计思路和我们的WebApi中的Program.cs特别像,然后使用起来就更加简单了:

 using var server = await ArticleScenariosBase.GetTestHost().StartAsync();// Action 发起接口请求var response = await server.GetTestClientWithToken().GetAsync("/api/blogs?page=1&pageSize=5");// Assert 确保接口状态码是200response.EnsureSuccessStatusCode();

  这种方案不仅兼容了第二种方案的优点,而且对之前我们设计的Autofac依赖注入容器没有做任何的修改。

所以这种方案做集成测试我给:
⭐⭐⭐⭐⭐

编者按:Blog.Core开源三周年

【原料】

 个人开源项目Blog.Core马上就已经开源三周年了,经过许许多多的小伙伴功能努力的结果,希望给ASP.NET Core在国内的推广,提供一个落地级别的案例。

【制法】

 A、累计提交上千次Commit;

 B、配合前、后、认证、鉴权一体化方案;

 C、不完全统计,被60+公司使用中;

【调味】

1.希望更多的小伙伴参与并提交PR。

2.希望更多的公司和组织使用,提供宝贵生产意见。

3.希望可以得到组织的孵化,让项目更进一步,有意者可以联系我

Tips: 九月新内容,敬请期待。

HAPPY EVEY DAY!

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

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

相关文章

爱泼斯坦事件发酵,MIT师生发起抗议逼迫校长Rafael Reif辞职

全世界只有3.14 %的人关注了青少年数学之旅爱泼斯坦自杀引发的美国学术界地震持续发酵&#xff0c;其中涉及最深的无疑是MIT。继MIT媒体实验室主任Joi Ito和计算机科学家Richard Stallman先后迫于压力辞职后&#xff0c;现任MIT校长Rafael Reif正面临越来越大的辞职压力。现年6…

小诗

我是天空中的片云&#xff0c;你是彩云中的红霞&#xff0c; 芸芸中相遇&#xff0c;不经然相识&#xff0c; 霞是美丽的&#xff0c;风中带着你的气息&#xff0c; 让我常常大口吸进生活活力&#xff0c;想着&#xff0c;伴着&#xff0c;缠着。一起漂浮在美丽天宇内&#xff…

Oracle索引扫描四大类的分析

学习Oracle时&#xff0c;你可能会遇到Oracle索引扫描问题&#xff0c;这里将介绍Oracle索引扫描问题的解决方法&#xff0c;在这里拿出来和大家分享一下。根据索引的类型与where限制条件的不同&#xff0c;有4种类型的Oracle索引扫描&#xff1a;◆索引唯一扫描(index unique …

java file_java开发之File类详细使用方法介绍

File类简介在 Java 中&#xff0c;File 类是 java.io 包中唯一代表磁盘文件本身的对象。File 类定义了一些与平台无关的方法来操作文件&#xff0c;File类主要用来获取或处理与磁盘文件相关的信息&#xff0c;像文件名、 文件路径、访问权限和修改日期等&#xff0c;还可以浏览…

食疗去除头屑的小偏方 不错!

饮食去头屑 除了好产品和生活上的调理&#xff0c;通过饮食也可以控制或治疗头皮屑。蔬菜粥&#xff1a;适用“血虚风燥型”材料&#xff1a;菠菜50克、大米50克。做法&#xff1a;将菠菜洗净&#xff0c;煮去涩味&#xff0c;切段备用。再将白米淘净&#xff0c;放入锅内&…

使用 Blazor 开发内部后台(二):了解 Blazor 组件

James: 转载技术社区中一位朋友最新的文章&#xff0c;介绍自己为公司的 WebForm 遗留系统使用 Blazor 重写前端 UI 的经历。什么是Blazor组件Blazor 应用是使用 Razor 组件构建的。组件是用户界面 (UI) 的自包含部分&#xff0c;具有用于启用动态行为的处理逻辑。组件可以嵌套…

Eclipse/Myeclipse生成serialVersionUID方法

serialVersionUID作用&#xff1a;   序列化时为了保持版本的兼容性&#xff0c;即在版本升级时反序列化仍保持对象的唯一性。 如果你修改代码重新部署后出现序列化错误&#xff0c;可以考虑给相应的类增加serialVersionUID字段。 一般来说有两种生成方式&#xff1a;  …

Framework 1.0/1.1中NotifyIcon的不足

.NET Framework 1.0/1.1中给我们提供了一个NotifyIcon类&#xff0c;使用这个类我们可以非常方便的实现系统托盘(SystemTray)图标。可是不知道微软是为了兼容性还是为了偷懒&#xff0c;只实现了NOTIFYICONDATA结构的v5.0之前版本&#xff0c;也就是说不支持5.0及以后的balloon…

pl/sql 中关于exception的学习笔记

1、异常的优点如果没有异常&#xff0c;在程序中&#xff0c;应当检查每个命令的成功还是失败&#xff0c;如BEGINSELECT ...-- check for ’no data found’ errorSELECT ...-- check for ’no data found’ errorSELECT ...-- check for ’no data found’ error这种实现的方…

一文读懂 .NET 中的高性能队列 Channel

介绍System.Threading.Channels 是.NET Core 3.0 后推出的新的集合类型, 具有异步API,高性能&#xff0c;线程安全等特点&#xff0c;它可以用来做消息队列&#xff0c;进行数据的生产和消费, 公开的 Writer 和 Reader api对应消息的生产者和消费者&#xff0c;也让Channel更加…

java字符数组初始化_Java 字符串(一)字符串初始化

一、String类概述1、概述java.lang.String类代表字符串。Java程序中所有的字符串文字(例如 "abc" )都可以被看作是实现此类的实例。String 是引用数据类型&#xff0c;不是基本数据类型。类String 中包括用于检查各个字符串的方法&#xff0c;比如用于比较字符串&…

一晚啪了5只喵,累到在医院打点滴,这中国喵把英国人看傻了 | 今日最佳

世界只有3.14 % 的人关注了青少年数学之旅最近&#xff0c;一只叫xiaopi的中国猫在英国红了&#xff01;好多媒体都报道了它…“猫咪一夜连XX 5只母喵后&#xff0c;累到挂点滴”《LADbible》&#xff0c;《Mirror》都可以看到它疲惫的小脸蛋…在《每日邮报》&#xff0c;xiaop…

放假的第二天

嗯...今天是放假的第二天.感觉昨天过了好漫长的一天哦,长得都有好几年了....昨天早上和某军去爬山,蛮惊喜的实话的说,可是快到山顶的时候罗打电话给某军说高二化学(2)要照相,某军却骗她说他正和一男孩儿爬山,男孩儿.....我....纠结.....后来过了好久,我们终于从山上下来了,赶到…

Locations Section of OpenCascade BRep

Locations Section of OpenCascade BRep eryar163.com 摘要Abstract&#xff1a;本文结合OpenCascade的BRep格式描述文档和源程序&#xff0c;对BRep格式进行分析&#xff0c;详细说明BRep的数据组织形式。本文主要通过对BRep文件中的Locations部分的读写代码进行分析&#xff…

2007武汉.NET俱乐部沙龙-VS2008、WPF、Silverlight

即将进入2008年&#xff0c;激动人心的一年。微软也将活跃起来&#xff0c;讨论微软技术发展的最新趋势&#xff0c;产品与解决方案的商业价值&#xff0c;新技术对未来行业的影响&#xff0c;使您以饱满的激情碰撞2008&#xff01;与此同时&#xff0c;微软又带给开发人员什么…

java long to float_为什么Java中long可以自动转换成float

Java中&#xff0c;long型是64位的&#xff0c;float型是32位的。为什么long型可以自动转float型呢?这里就涉及到浮点数在内存中的存储问题了。对于byte&#xff0c;short&#xff0c;int&#xff0c;long四个整数类型而言&#xff0c;它们在内存中无一例外都是直接换算成二进…

C# 枚举(Enum)

在数学和计算机科学理论中&#xff0c;一个集的枚举是列出某些有穷序列集的所有成员的程序&#xff0c;或者是一种特定类型对象的计数。这两种类型经常&#xff08;但不总是&#xff09;重叠。[1] 是一个被命名的整型常数的集合&#xff0c;枚举在日常生活中很常见&#xff0c…

孙悟空都服输!波士顿动力最新逆天机器人视频,翻筋斗连拿大顶!

全世界只有3.14 %的人关注了青少年数学之旅刚刚&#xff0c;波士顿动力公司在YouTube发布了两段真正震撼的新视频&#xff1a;双足人形机器人Atlas展示倒立、360度翻跟头、旋转的跑酷Demo&#xff1a;More Parkour Atlas。四足机器人Spot的商业化广告宣传片&#xff1a;Spot La…

痛并快乐着

看到访问量不断增加&#xff0c;而且访问过的人数已经超过500人&#xff08;注意不是浏览次数&#xff0c;而是不同的人数&#xff09;&#xff0c;真有成就感。与此同时&#xff0c;申请网易联盟再次失败&#xff0c;决定好好写我自己的blog&#xff0c;不再去管他什么狗屁联盟…

C#实例:datagridview单元格合并

这是替C#微信交流群群友做的一个小实例&#xff0c;目的就是在datagridview选择对应行以后&#xff0c;点击button后获取对应行的ip&#xff0c;并执行相应的操作&#xff0c;其实我觉得这样的话button没必要非放置到datagridview里面的&#xff01;但是为了满足群友的需求&…