本文需要您了解ASP.NET Core MVC/Web API, xUnit以及Moq相关知识.

这里有xUnit和Moq的介绍: https://www.cnblogs.com/cgzl/p/9178672.html#test

Controllers可以说是ASP.NET Core MVC/Web API项目的核心, 它们把整个应用都整合到了一起. 可以说Controllers是非常重要的, 所以我们应该对它们做一些测试.

由于我几乎只做API, 所以本文不包括关于MVC功能的测试, 只包括Controller的API相关功能.

测试一个简单的Controller

先举一个简单点的例子:

这个Controller相对简单, 它有一个依赖项.

它一个方法, 返回类型是IActionResult, 又具体分为两种情况.

测试返回结果的类型

首先需要new出来一个被测试的RootController, 标准的叫法叫System Under Test(被测试系统). 它需要一个urlHelper作为依赖项, 那就Mock一个即可.

每组测试数据都会走一遍构造函数的.

该测试方法使用的是Theory, 用了4组数据. 执行方法后返回的结果类型应该实现了IActionResult接口, 这里可以用Assert.IsAssignableFrom<TExpected>(actual)来判断.

注: 为了方便, 我使用了resharper.

测试之前一定要重新Build一下.

然后再点击resharper在方法旁边提供的测试按钮即可:

从图可以看出resharper提供了方便快捷的图标, 在这你可以选择运行或者调试测试.

测试会通过的, Theory下属的4组数据将被视为4个单独的测试:

针对该方法的其它测试

我又添加了两个测试方法, 来测试该方法的不同路径及返回结果:

通常一个测试方法里应该只有一个Assert. 但是第二方法里面有两个Assert, 这是因为这两个Assert都是测试的同一个行为, 所以我认为这样应该是可以的.

Rebuild, 测试:

也是OK的.

看起来针对RootController的GetRoot()方法, 我们好像已经测试了所有可执行的路径. 让我们使用测试代码覆盖率这个功能来确定一下.

点击resharper在测试类旁边提供的CoverAll按钮:

随后会出现单元测试窗口和覆盖率窗口.

直接看覆盖率窗口:

可以看到该Controller和方法的覆盖率都是100%了.

来到被测试的RootController里:

Resharper(实际上是dotCover) 在代码的左边显示出了该行代码是否已经被测试覆盖, 如果都是绿色的就说明都被覆盖了.

导出覆盖率结果

Resharper的代码覆盖率结果可以导出多种格式:

例如导出HTML后也可以查看覆盖率明细:

测试复杂一点的Controller

这个ProductController略微复杂一点, 首先它需要很多依赖项.

看它的POST Action方法, 很多地方需要被测试:

测试ModelState

首先可以测试product为null的情况, 但是这个太简单了, 我就不啰嗦了.

那就测试ModelState.Invalid情况吧:

为了让ModelState Invalid, 我手动添加了ModelState的error. 和被测试方法其它必要的参数.

该方法有三个Assert, 首先判定结果类型是否为UnprocessableEntityObjectResult(422状态码), 然后再判定返回结果包含了ModelState的error.

该测试会pass, 并会覆盖这部分相关的代码:

测试特定方法会被调用

这里需要使用moq了, 为了让被测试方法顺利跑完, 我设定Mock版的UnitOfWork的SaveAsync()方法会返回true, (注意这个方法的返回类型是Task<bool>):

然后通过moq的Verify()方法判定repository的AddProduct()和unitOfWork的SaveAsync()方法分别被调用了.

Build, 测试会pass, 覆盖率目前比较大了(但是覆盖率100%并不能说明代码没问题):

模拟SaveAsync()后的实体数据

该项目使用的是EFCore, 在_unitOfWorkSaveAsync()之后, 变量productModel的Id就会有非0值了, 也就是说productModel在_unitOfWorkSaveAsync()方法执行之后发生了变化.

针对这种情况, 我们可以使用moq的Callback()功能:

刚开始为autoMapper的两次map动作设定了返回值.

然后在UnitOfWork的SaveAsync()执行后有个Callback()回调, 回调时相当于模拟了EFCore的保存, 把最新的值赋给了productModel(看被测试代码), (其实这里不用Callback也行....).

随后就是一系列的Assert, 判定某些方法是否执行, 返回类型是否正确, 返回的数据是否正确等.

Build 测试会通过的:

其它路径的测试

目前该方法还有两处地方没有被覆盖:

可以再写两个测试来覆盖它们:

这两个很简单, 不多介绍了, 注意这里使用了async版本的Assert.Throws().

这两个测试会pass, 最终该方法的代码覆盖率就达到100%了:

ASP.NET Core Web API Controller的测试就介绍这些吧.

测试 ASP.NET Core API Controller的更多相关文章

  1. 使用TestServer测试ASP.NET Core API

    今儿给大家分享下,在ASP.NET Core下使用TestServer进行集成测试,这意味着你可以在没有IIS服务器或任何外部事物的情况下测试完整的Web应用程序.下面给出示例: public Sta ...

  2. ASP.NET Core API 接收参数去掉烦人的 [FromBody]

    在测试ASP.NET Core API 项目的时候,发现后台接口参数为类型对象,对于PostMan和Ajax的Post方法传Json数据都获取不到相应的值,后来在类型参数前面加了一个[FromBody ...

  3. 详解ASP.NET Core API 的Get和Post请求使用方式

    上一篇文章帮助大家解决问题不彻底导致博友使用的时候还是遇到一些问题,欢迎一起讨论.所以下面重点详细讲解我们常用的Get和Post请求( 以.net core2.2的Http[Verb]为方向 ,推荐该 ...

  4. ASP.NET CORE API Swagger+IdentityServer4授权验证

    简介 本来不想写这篇博文,但在网上找到的文章博客都没有完整配置信息,所以这里记录下. 不了解IdentityServer4的可以看看我之前写的入门博文 Swagger 官方演示地址 源码地址 配置Id ...

  5. 使用 SoapUI 测试ASP.NET Web API

    我们为不同的目的开发了很多web服务,经过授权的用户就可以访问和使用这些web服务.soapUI 是一个强大的测试web服务的工具,他不仅可以测试SOAP服务,他也支持测试RESTful服务.在这里我 ...

  6. ASP.NET Core API ——Dapper的使用

    ASP.NET Core API ——Dapper的使用 简介:Dapper是一个ORM框架,负责数据库和程序语言之间的映射. 使用步骤: l  创建一个IDBConnection的接口对象 l  编 ...

  7. ASP.NET Core API总结(一)

    ASP.NET Core API 问题:当应用收到一个http请求之后,API应用程序是怎么一步步执行的. 注册服务——构造容器——使用服务——创建对象 1.         创建一个新的API之后, ...

  8. Asp.Net Core 减少Controller获取重复注入对象

    原文:Asp.Net Core 减少Controller获取重复注入对象 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u012770274/art ...

  9. How to read request body in a asp.net core webapi controller?

    原文 How to read request body in a asp.net core webapi controller? A clearer solution, works in ASP.Ne ...

随机推荐

  1. JavaScript Array+String对象的常用方法

    Array 对象 Array 对象用于在单个的变量中存储多个值. 创建 Array 对象的语法: new Array(); new Array(size); new Array(element0, e ...

  2. Nginx安装及配置详解

    nginx概述 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:nginx可以作为一个HTTP服务器进行网站的发布处理,另外 ...

  3. [UOJ#207. 共价大爷游长沙]——LCT&随机化

    题目大意: 传送门 给一颗动态树,给出一些路径并动态修改,每次询问一条边是否被所有路径覆盖. 题解: 先%一发myy. 开始感觉不是很可做的样子,发现子树信息无论维护什么都不太对…… 然后打开题目标签 ...

  4. 【BZOJ 2004】: [Hnoi2010]Bus 公交线路

    题目链接: TP 题解:   所以说,超显眼的数据范围啊. 很显然我们对于每个P的区间都是要有k个站被bus停留,然后考虑转移的话应该是把这k个站里的某个bus往前走,那么转移也很显然了,n的范围很大 ...

  5. bzoj [HNOI2008]Cards

    群论第一题. 发现这题也是有颜色个数限制的,所以不能用$Polya$,只能用$Burnside$ $L={\frac{1}{|G|}}{\sum_{i=1}^{m}{D(a_{i})}}$ 先$dfs ...

  6. 映射内网ftp服务器到公网后内网访问出错问题

    上文说道映射后外网无法访问解决:https://www.cnblogs.com/Dev0ps/p/9073048.html 添加了ftp的pasv_address的地址 ,内网客户端要设置主动模式(a ...

  7. TF.learn学习

    官网地址:https://www.tensorflow.org/versions/r1.1/get_started/tflearn 1.代码例子 实现自定义的Estimator 使用DNNClassi ...

  8. 深入理解java虚拟机之垃圾收集器

    Java一个重要的优势就是通过垃圾管理器GC (Garbage Collection)自动管理和回收内存,程序员无需通过调用方法来释放内存.也因此很好多的程序员可能会认为Java程序不会出现内存泄漏的 ...

  9. eShopOnContainers 知多少[9]:Ocelot gateways

    引言 客户端与微服务的通信问题永远是一个绕不开的问题,对于小型微服务应用,客户端与微服务可以使用直连的方式进行通信,但对于对于大型的微服务应用我们将不得不面对以下问题: 如何降低客户端到后台的请求数量 ...

  10. Spark学习之编程进阶总结(二)

    五.基于分区进行操作 基于分区对数据进行操作可以让我们避免为每个数据元素进行重复的配置工作.诸如打开数据库连接或创建随机数生成器等操作,都是我们应当尽量避免为每个元素都配置一次的工作.Spark 提供 ...