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…

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

File类简介在 Java 中&#xff0c;File 类是 java.io 包中唯一代表磁盘文件本身的对象。File 类定义了一些与平台无关的方法来操作文件&#xff0c;File类主要用来获取或处理与磁盘文件相关的信息&#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…

一文读懂 .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…

Locations Section of OpenCascade BRep

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

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

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

C#实例:datagridview单元格合并

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

NO.106 需求的状态、研发阶段及注意事项。

为什么80%的码农都做不了架构师&#xff1f;>>> 禅道项目管理软件设计的需求有两个字段来跟踪它的变化&#xff0c;一个是需求的状态字段&#xff0c;一个是需求的研发阶段字段&#xff0c;下面来看下这两个字段。 一、需求的状态 需求状态(status)字段&#xff0c…

java实例化泛型_Java让泛型实例化的方法

泛型对象可以实例化吗&#xff1f;不可以&#xff0c;T tnew T()是不可以的&#xff0c;编译器会报错。由于泛型擦除&#xff0c;编译器在编译时无法确定泛型所对应的真实类型解决方法使用反射新建实例Type superclass getClass().getGenericSuperclass();ParameterizedType p…

几种人类设计的永动机,最后一个彻底服了!| 今日最佳

全世界只有3.14 %的人关注了青少年数学之旅众所周知&#xff0c;永动机是违反当前客观科学规律的概念&#xff0c;是永远不能够被制造出来的。下面这些都是人们根据不同原理设计出来的&#xff0c;看一看有什么神奇之处&#xff0c;最后一个是亮点&#xff01;▲达芬奇设计的永…

剖析WPF依赖属性

这节来讲一下WPF中的依赖属性 (Dependency Property)。【了解属性和字段】我们知道&#xff0c;属性是面向对象语言中用来封装字段的外衣&#xff0c;它像是字段对外界的桥梁&#xff0c;我们可以通过属性来验证数据的合法性或控制对外的访问性等等。每个属性的背后都有其对应的…

你在孩子身上偷的懒,终将会变成最大的遗憾

全世界只有3.14 %的人关注了青少年数学之旅我们来看一个非常有趣的统计&#xff1a;2007年—2016年全国高考状元父母职业统计最优秀的孩子大多数出自教师家庭。很家长说&#xff0c;教师有着和孩子一样的寒暑假&#xff0c;有着教书育人的先天优势&#xff0c;我们普通人工作忙…

开发们 点广告-赚点BT币

2019独角兽企业重金招聘Python工程师标准>>> http://freebitco.in/?r14320 转载于:https://my.oschina.net/wangtao/blog/180765

Asp.net页面的生命周期

介绍Asp.net是微软.Net战略的一个组成部分。它相对以前的Asp有了很大的发展&#xff0c;引入了许多的新机制。本文就Asp.net页面的生命周期向大家做一个初步的介绍&#xff0c;以期能起到指导大家更好、更灵活地操纵Asp.net的作用。当一个获取网页的请求&#xff08;可能是通过…

太赞了!微软《dotnet中文手册》火了,完整PDF开放下载!

这是微软高级架构师基于最新的.net编写&#xff0c;循序渐进地对.net/C#进行讲解。对于零基础可以作为.net的快速入门教材&#xff0c;对于高级程序员而言&#xff0c;这也是你的进阶之路&#xff0c;今天来了&#xff0c;就是缘份&#xff0c;看到了就送给你&#xff01;资料介…

你穿衣品味还不如AI,这有一款时尚着装网络模型

全世界只有3.14 %的人关注了青少年数学之旅有一件衣服的时候&#xff0c;怎样的小改动可以提升其整体的时尚性&#xff1f;近日 UT 奥斯汀、康奈尔大学、乔治亚理工和 Facebook AI 研究中心的研究者提出了一种名为 Fashon 的模型&#xff0c;用于给一件衣服进行改进&#xff0…