单元测试

本篇将结合这个系列的例子的基础上演示在Asp.Net Core里如何使用XUnit结合Moq进行单元测试,同时对整个项目进行集成测试。

第一部分、XUnit

修改 Project.json 文件内容,增加XUnit相关的nuget包引用,并修改部分配置。

 1 {
2 "version": "1.0.0-*",
3 "testRunner": "xunit", // 设置测试工具为xunit
4
5 "buildOptions": {
6 "debugType": "portable",
7 "emitEntryPoint": true
8 },
9 "dependencies": {
10 "Microsoft.NETCore.App": {
11 "type": "platform",
12 "version": "1.0.0"
13 },
14 "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
15 "Microsoft.AspNetCore.Mvc": "1.0.0",
16 "Microsoft.Extensions.Logging": "1.0.0",
17 "Microsoft.Extensions.Logging.Console": "1.0.0",
18 "Microsoft.Extensions.Logging.Debug": "1.0.0",
19 "Microsoft.Extensions.Logging.Filter": "1.0.0",
20 "NLog.Extensions.Logging": "1.0.0-rtm-alpha2",
21 "Autofac.Extensions.DependencyInjection": "4.0.0-rc3-309",
22 "Microsoft.Extensions.Configuration": "1.0.0",
23 "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
24 "Microsoft.Extensions.Configuration.Json": "1.0.0",
25 "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
26 "xunit": "2.2.0-beta2-build3300",
27 "dotnet-test-xunit": "2.2.0-preview2-build1029"
28 },
29 "frameworks": {
30 "netcoreapp1.0": {
31 // 设置兼容框架
32 "imports": [
33 "dotnet54",
34 "portable-net45+win8"
35 ]
36 }
37 }
38 }

增加一个Demo类和一个测试类

 1 namespace WebApiFrame
2 {
3 public class DemoModel
4 {
5 public int Add(int a, int b)
6 {
7 return a + b;
8 }
9
10 public bool IsOdd(int num)
11 {
12 return num % 2 == 1;
13 }
14 }
15 }
 1 using Xunit;
2
3 namespace WebApiFrame.Test
4 {
5 public class DemoModelTest
6 {
7 private readonly DemoModel _demo;
8
9 public DemoModelTest()
10 {
11 _demo = new DemoModel();
12 }
13
14 [Fact]
15 public void AddTest()
16 {
17 int result = _demo.Add(1, 2);
18 Assert.Equal(3, result);
19 }
20 }
21 }

打开cmd窗口,进入到项目根目录,输入命令 dotnet test ,将启动单元测试,可以在输出查看测试结果

再对另外一个方法添加单元测试代码

1         [Theory]
2 [InlineData(1)]
3 [InlineData(2)]
4 [InlineData(3)]
5 public void IsOdd(int num)
6 {
7 bool result = _demo.IsOdd(num);
8 Assert.True(result, $"{num} is not odd.");
9 }

再次启动单元测试,查看测试结果

结果显示执行了四个单元测试用例,有一个失败了。

通过比较上面两个测试方法可以发现使用的特性标识不同,测试方法的参数列表也不相同。

[Face]特性标识表示固定输入的测试用例,而[Theory]特性标识表示可以指定多个输入的测试用例,结合InlineData特性标识使用。在上面的例子里,总共使用了三次InlineData特性标识,每次设定的值都不同,在执行单元测试时,设定的值会被测试框架赋值到对应的测试方法的参数里。

第二部分、Moq

在之前的例子里已经定义了如下接口和类

 IUserRepository.cs
 UsersController.cs

我们要对 UsersController.cs 的方法进行单元测试,同时UserRepository实例是通过构造函数依赖注入的,所以要借助Moq来模拟这个实例的生成。

在引入Moq包之前,先要修改NuGet.Config配置文件,增加package包源地址。

NuGet.Config配置文件路径: C:\Users\{user}\AppData\Roaming\NuGet

 1 <?xml version="1.0" encoding="utf-8"?>
2 <configuration>
3 <activePackageSource>
4 <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
5 </activePackageSource>
6 <packageSources>
7 <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
8
9 <!-- 增加的程序包源地址 -->
10 <add key="aspnet-contrib" value="https://www.myget.org/F/aspnet-contrib/api/v3/index.json" />
11 </packageSources>
12 </configuration>

引入Moq相关nuget包: "moq.netcore": "4.4.0-beta8"

添加单元测试类

 1 using System.Collections.Generic;
2 using System.Linq;
3 using Microsoft.AspNetCore.Mvc;
4 using Moq;
5 using WebApiFrame.Controllers;
6 using WebApiFrame.Models;
7 using WebApiFrame.Repositories;
8 using Xunit;
9
10 namespace WebApiFrame.Test
11 {
12 public class UsersControllerTest
13 {
14 private readonly UsersController _controller;
15
16 public UsersControllerTest()
17 {
18 var mockRepo = new Mock<IUserRepository>();
19 mockRepo.Setup(repo => repo.GetAll()).Returns(GetUsers());
20 _controller = new UsersController(mockRepo.Object);
21 }
22
23 [Fact]
24 public void GetAllTest()
25 {
26 IActionResult actionResult = _controller.GetAll();
27 var objectResult = Assert.IsType<ObjectResult>(actionResult);
28 var result = Assert.IsAssignableFrom<IEnumerable<User>>(objectResult.Value);
29 Assert.Equal(3, result.Count());
30 }
31
32 private IEnumerable<User> GetUsers()
33 {
34 return new List<User>()
35 {
36 new User(){ Id = 1, Name = "name:1", Sex = "Male" },
37 new User(){ Id = 2, Name = "name:2", Sex = "Female" },
38 new User(){ Id = 3, Name = "name:3", Sex = "Male" },
39 };
40 }
41 }
42 }

在cmd窗口执行单元测试,查看测试结果

在一个分层结构清晰的项目里,各层之间依赖于事先约定好的接口。在多人协作开发时,大多数人都只会负责自己的那一部分模块功能,开发进度通常情况下也不一致。当某个开发人员需要对自己的模块进行单元测试而依赖的其他模块还没有开发完成时,则需要对依赖的接口通过Mock的方式提供模拟功能,从而达到在不实际依赖其他模块的具体功能的情况下完成自己模块的单元测试工作。

第三部分、集成测试

以上的例子只是对逻辑进行了单元测试。对于Asp.Net Core项目,还需要模拟在网站部署的情况下对各个请求入口进行测试。通常情况下可以借助Fiddler等工具完成,在.Net Core里也可以用编程的方式完成测试。

首先引入测试需要的nuget包。因为我们测试的是WebApi接口,响应内容都是json格式的字符串,所以还需要引用json序列化的nuget包。

    "Microsoft.AspNetCore.TestHost": "1.0.0",
"Newtonsoft.Json": "9.0.1"

添加测试类

 1 using System.Collections.Generic;
2 using System.Net.Http;
3 using System.Threading.Tasks;
4 using Microsoft.AspNetCore.Hosting;
5 using Microsoft.AspNetCore.TestHost;
6 using Newtonsoft.Json;
7 using WebApiFrame.Models;
8 using Xunit;
9
10 namespace WebApiFrame.Test
11 {
12 public class WebApiFrameTest
13 {
14 private readonly TestServer _server;
15 private readonly HttpClient _client;
16
17 public WebApiFrameTest()
18 {
19 _server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
20 _client = _server.CreateClient();
21 }
22
23 [Fact]
24 public async Task GetAllTest()
25 {
26 var response = await _client.GetAsync("/api/users");
27 response.EnsureSuccessStatusCode();
28
29 var responseString = await response.Content.ReadAsStringAsync();
30 IList<User> users = JsonConvert.DeserializeObject<IList<User>>(responseString);
31
32 Assert.Equal(3, users.Count);
33 }
34
35 [Theory]
36 [InlineData(1)]
37 [InlineData(2)]
38 [InlineData(3)]
39 public async Task GetTest(int id)
40 {
41 var response = await _client.GetAsync($"/api/users/{id}");
42 response.EnsureSuccessStatusCode();
43
44 var responseString = await response.Content.ReadAsStringAsync();
45 User user = JsonConvert.DeserializeObject<User>(responseString);
46
47 Assert.NotNull(user);
48 }
49 }
50 }

在cmd窗口执行单元测试,查看测试结果

在上面的例子里,通过在一个工程里同时模拟了服务端(TestServer)和客户端(HttpClient)的通信,从而达到了整体测试WebApi接口的目的。

Net Core WebApi单元测试的更多相关文章

  1. 使用 xUnit 编写 ASP.NET Core WebAPI单元测试

    本文使用xUnit对ASP.NET Core WebAPI做单元测试,使用HttpClient的同步和异步请求,下面详细介绍xUnit的使用过程: 一.创建示例项目 模板为我们自动创建了一个Value ...

  2. asp.net core webapi/website+Azure DevOps+GitHub+Docker

    asp.net core webapi/website+Azure DevOps+GitHub+Docker 新春开篇作,主要写一下关于asp.net core web/api 2.2 项目借助dev ...

  3. ASP.NET Core WebAPI控制器返回类型的最佳选项

    前言 从.NET Core 2.1版开始,到目前为止,控制器操作可以返回三种类型的WebApi响应.这三种类型都有自己的优点和缺点,但都缺乏满足REST和高可测性的选项. ASP.NET Core中可 ...

  4. 【WebAPI】从零开始学会使用.NET Core WebAPI

    介绍 以后会慢慢总结在项目使用中或者学习到的webAPI相关的知识,在这里做记录. 我会从最开始的如何创建WebAPI项目到项目的后续知识一点一点的开始讲述记录. 通过简单有效的方式,让我们能够快速的 ...

  5. 使用xunit对asp.net core webapi进行集成测试

    新项目我们采用前后端分离,后端采用asp.net core webapi, 如何对后端代码进行自动化测试呢,有以下几种方案: 1. 单元测试,目前这个方案对我们来说难度很大,抛开时间的问题,单元测试对 ...

  6. .Net Core WebAPI 基于Task的同步&异步编程快速入门

    .Net Core WebAPI 基于Task的同步&异步编程快速入门 Task.Result async & await 总结 并行任务(Task)以及基于Task的异步编程(asy ...

  7. asp.net core webapi之跨域(Cors)访问

    这里说的跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作 ...

  8. ASP.NET Core WebAPI 开发-新建WebAPI项目

    ASP.NET Core WebAPI 开发-新建WebAPI项目, ASP.NET Core 1.0 RC2 即将发布,我们现在来学习一下 ASP.NET Core WebAPI开发. 网上已经有泄 ...

  9. Asp.net Core WebApi 使用Swagger做帮助文档,并且自定义Swagger的UI

    WebApi写好之后,在线帮助文档以及能够在线调试的工具是专业化的表现,而Swagger毫无疑问是做Docs的最佳工具,自动生成每个Controller的接口说明,自动将参数解析成json,并且能够在 ...

随机推荐

  1. Proud Merchants(POJ 3466 01背包+排序)

    Proud Merchants Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) ...

  2. ASP.NET MVC 4.0 学习3-Model

    Model負責獲取數據庫中的資料,並對數據庫中的數據進行處理. MVC中有關 數據庫 的任務都由Model來完成,Model中對數據資料進行定義,Controller和View中都會參考到Model, ...

  3. mysql 执行reset master 风险

    reset master 会把mysql实例上的所以二进制日志删除,并且日志序列从1开始:这样会引起两个问题. 001.问题一 slave 由于找不到下一个要执行的事件所以会报错.进一步master- ...

  4. STM32之------独立看门狗(IWDG)和窗体看门狗(WWDG)

    一     前沿废语: 之前有很风靡的游戏,名字叫<看门狗>.该游戏用了很新的引擎技术,打造出了一个辽阔庞大的世界,内容是玩家Aiden·Pearce(主角)是一名精通黑客技术的高手,当时 ...

  5. 大端模式&小端模式、主机序&网络序、入栈地址高低问题

    一.大端模式&小端模式 所谓的“大端模式”,是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处 ...

  6. windows 7 系统进程服务详解

    windows 7已经发布有段时间了,相信很多网友都已经换上了传说中非常完美的win7系统.win7不仅继承而且还超越了vista的美观界面,性能优化方面也下足了功力.还拥有强大的win xp兼容性, ...

  7. jQuery之Jcrop

    头像裁剪是一个经常用到的功能,实现原理也较为简单,就是在本地选择好所需裁剪图片的坐标,将坐标发送到服务器,由服务器执行图片裁剪操作. jQuery插件Jcrop提供了强大的图片裁剪坐标选择插件.一下来 ...

  8. 使用 asp.net Web API 2的坑

    使用工具: Googl  浏览器+PostMan 插件 写了个  控制器 添加了个Action,结果呢?GET 方式请求没问题. POST一直,在服务器端获取不了参数...找了官方的文档 .各种雨里雾 ...

  9. HDU 5775 Bubble Sort(线段树)(2016 Multi-University Training Contest 4 1012)

    原址地址:http://ibupu.link/?id=31 Problem Description P is a permutation of the integers from 1 to N(ind ...

  10. UESTC_酱神赏花 2015 UESTC Training for Dynamic Programming<Problem C>

    C - 酱神赏花 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 262143/262143KB (Java/Others) Submi ...