您的位置:首页 > 编程语言 > ASP

使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(九)-- 单元测试

2016-07-31 23:44 1116 查看

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


第一部分、XUnit

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

{
"version": "1.0.0-*",
"testRunner": "xunit",  // 设置测试工具为xunit

"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
},
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Logging.Filter": "1.0.0",
"NLog.Extensions.Logging": "1.0.0-rtm-alpha2",
"Autofac.Extensions.DependencyInjection": "4.0.0-rc3-309",
"Microsoft.Extensions.Configuration": "1.0.0",
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"xunit": "2.2.0-beta2-build3300",
"dotnet-test-xunit": "2.2.0-preview2-build1029"
},
"frameworks": {
"netcoreapp1.0": {
// 设置兼容框架
"imports": [
"dotnet54",
"portable-net45+win8"
]
}
}
}


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

namespace WebApiFrame
{
public class DemoModel
{
public int Add(int a, int b)
{
return a + b;
}

public bool IsOdd(int num)
{
return num % 2 == 1;
}
}
}


using Xunit;

namespace WebApiFrame.Test
{
public class DemoModelTest
{
private readonly DemoModel _demo;

public DemoModelTest()
{
_demo = new DemoModel();
}

[Fact]
public void AddTest()
{
int result = _demo.Add(1, 2);
Assert.Equal(3, result);
}
}
}


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

using System;
using Microsoft.AspNetCore.Mvc;
using WebApiFrame.Models;
using WebApiFrame.Repositories;

namespace WebApiFrame.Controllers
{
[Route("api/[controller]")]
public class UsersController : Controller
{
private readonly IUserRepository userRepository;

public UsersController(IUserRepository userRepo)
{
userRepository = userRepo;
}

[HttpGet]
public IActionResult GetAll()
{
var list = userRepository.GetAll();
return new ObjectResult(list);
}

[HttpGet("{id}")]
public IActionResult Get(int id)
{
var user = userRepository.GetById(id);
return new ObjectResult(user);
}

#region 其他方法
// ......
#endregion
}
}


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

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

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

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<activePackageSource>
<add key="nuget.org" value="https://www.nuget.org/api/v2/" />
</activePackageSource>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />

<!-- 增加的程序包源地址 -->
<add key="aspnet-contrib" value="https://www.myget.org/F/aspnet-contrib/api/v3/index.json" />
</packageSources>
</configuration>


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

添加单元测试类

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Moq;
using WebApiFrame.Controllers;
using WebApiFrame.Models;
using WebApiFrame.Repositories;
using Xunit;

namespace WebApiFrame.Test
{
public class UsersControllerTest
{
private readonly UsersController _controller;

public UsersControllerTest()
{
var mockRepo = new Mock<IUserRepository>();
mockRepo.Setup(repo => repo.GetAll()).Returns(GetUsers());
_controller = new UsersController(mockRepo.Object);
}

[Fact]
public void GetAllTest()
{
IActionResult actionResult = _controller.GetAll();
var objectResult = Assert.IsType<ObjectResult>(actionResult);
var result = Assert.IsAssignableFrom<IEnumerable<User>>(objectResult.Value);
Assert.Equal(3, result.Count());
}

private IEnumerable<User> GetUsers()
{
return new List<User>()
{
new User(){ Id = 1, Name = "name:1", Sex = "Male" },
new User(){ Id = 2, Name = "name:2", Sex = "Female" },
new User(){ Id = 3, Name = "name:3", Sex = "Male" },
};
}
}
}


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



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

第三部分、集成测试

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

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

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


添加测试类

using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Newtonsoft.Json;
using WebApiFrame.Models;
using Xunit;

namespace WebApiFrame.Test
{
public class WebApiFrameTest
{
private readonly TestServer _server;
private readonly HttpClient _client;

public WebApiFrameTest()
{
_server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
_client = _server.CreateClient();
}

[Fact]
public async Task GetAllTest()
{
var response = await _client.GetAsync("/api/users");
response.EnsureSuccessStatusCode();

var responseString = await response.Content.ReadAsStringAsync();
IList<User> users = JsonConvert.DeserializeObject<IList<User>>(responseString);

Assert.Equal(3, users.Count);
}

[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public async Task GetTest(int id)
{
var response = await _client.GetAsync($"/api/users/{id}");
response.EnsureSuccessStatusCode();

var responseString = await response.Content.ReadAsStringAsync();
User user = JsonConvert.DeserializeObject<User>(responseString);

Assert.NotNull(user);
}
}
}


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



在上面的例子里,通过在一个工程里同时模拟了服务端(TestServer)和客户端(HttpClient)的通信,从而达到了整体测试WebApi接口的目的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: