2020/02/01, ASP.NET Core 3.1, VS2019, xunit 2.4.1, Microsoft.AspNetCore.TestHost 3.1.1html
摘要:基於ASP.NET Core 3.1 WebApi搭建後端多層網站架構【12-xUnit單元測試之集成測試】
使用xUnit藉助TestServer進行集成測試,在單元測試中對WebApi的每一個接口進行測試git
文章目錄github
此分支項目代碼web
本章節介紹了使用xUnit藉助TestServer進行集成測試,在單元測試中對WebApi的每一個接口進行測試數據庫
在tests解決方案文件夾下新建xUnit單元測試,記得存放在實際tests路徑下,取名WebApiTestsjson
向WebApiTests
單元測試添加Microsoft.AspNetCore.TestHost
包引用:後端
<ItemGroup> <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.1.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="coverlet.collector" Version="1.2.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup>
添加Microsoft.AspNetCore.TestHost
包(3.1.1)引用,其餘默認的包升級到最新,具體版本參考上面
向WebApiTests
單元測試添加對MS.WebApi
的引用服務器
在WebApiTests
單元測試中添加TestHostBuild.cs
類,這是整個集成測試的核心部分:架構
using Autofac.Extensions.DependencyInjection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using MS.Component.Jwt; using MS.Component.Jwt.UserClaim; using MS.WebApi; using System.Net.Http; namespace WebApiTests { public static class TestHostBuild { public static readonly JwtService jwtService = new JwtService(Options.Create(new JwtSetting { Audience = "MS.Audience", Issuer = "MS.WebHost", LifeTime = 1440, SecurityKey = "MS.WebHost SecurityKey"//此處內容需和服務器appsettings.json中保持一致 })); public static readonly UserData userData = new UserData { Account = "test", Email = "test@qq.com", Id = 1, Name = "測試用戶", Phone = "123456789111", RoleDisplayName = "testuserRole", RoleName = "testuser" };//測試用戶的數據,也能夠改爲真實的數據,看需求 public static IHostBuilder GetTestHost() { //代碼和網站Program中CreateHostBuilder代碼很相似,去除了AddNlogService以避免跑測試生成不少日誌 //若是網站並無使用autofac替換原生DI容器,UseServiceProviderFactory這句話能夠去除 //關鍵是webBuilder中的UseTestServer,創建TestServer用於集成測試 return new HostBuilder() .UseServiceProviderFactory(new AutofacServiceProviderFactory())//替換autofac做爲DI容器 .ConfigureWebHostDefaults(webBuilder => { webBuilder .UseTestServer()//關鍵時多了這一行創建TestServer .UseStartup<Startup>(); }); } /// <summary> /// 生成帶token的httpclient /// </summary> /// <param name="host"></param> /// <returns></returns> public static HttpClient GetTestClientWithToken(this IHost host) { var client = host.GetTestClient(); client.DefaultRequestHeaders.Add("Authorization", $"Bearer {GenerateToken()}");//把token加到Header中 return client; } /// <summary> /// 生成jwt令牌 /// </summary> /// <returns></returns> public static string GenerateToken() { return jwtService.BuildToken(jwtService.BuildClaims(userData)); } } }
在WebApiTests
單元測試中添加ApiResult.cs
類:app
namespace WebApiTests { public class ApiResult<T> { public int status { get; set; } public T data { get; set; } } }
因爲咱們的接口返回值統一包裝了一層,因此構建了ApiResult用於反序列化接口返回值對象
在WebApiTests
單元測試中添加RoleControllerTest.cs
類,這是Role接口的測試用例:
using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Hosting; using MS.Common.Extensions; using MS.Entities; using MS.Models.ViewModel; using MS.WebCore.Core; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Xunit; namespace WebApiTests { public class RoleControllerTest { const string _testUrl = "/role/"; const string _mediaType = "application/json"; readonly Encoding _encoding = Encoding.UTF8; [Theory] [InlineData(1222538617050763264)] public async Task Delete_Id_ReturnResult(long id) { //arrange string url = $"{_testUrl}?id={id.ToString()}";// url: /role/?id=11111111 using var host = await TestHostBuild.GetTestHost().StartAsync();//啓動TestServer //act var response = await host.GetTestClientWithToken().DeleteAsync(url);//調用Delete接口 var result = (await response.Content.ReadAsStringAsync()).GetDeserializeObject<ApiResult<ExecuteResult>>();//得到返回結果並反序列化 //assert Assert.Equal(result.data.IsSucceed, string.IsNullOrWhiteSpace(result.data.Message)); } [Fact] public async Task Post_CreateRole_ReturnTrue() { //arrange RoleViewModel viewModel = new RoleViewModel { Name = "RoleForPostTest", DisplayName = "RoleForPostTest" }; StringContent content = new StringContent(viewModel.ToJsonString(), _encoding, _mediaType);//定義post傳遞的參數、編碼和類型 using var host = await TestHostBuild.GetTestHost().StartAsync();//啓動TestServer //act var response = await host.GetTestClientWithToken().PostAsync(_testUrl, content); //調用Post接口 var result = (await response.Content.ReadAsStringAsync()).GetDeserializeObject<ApiResult<ExecuteResult<Role>>>();//得到返回結果並反序列化 //assert Assert.True(result.data.IsSucceed); //測完把添加的刪除 await Delete_Id_ReturnResult(result.data.Result.Id); } [Fact] public async Task Put_UpdateRole_ReturnTrue() { //arrange RoleViewModel viewModel = new RoleViewModel { Name = "RoleForPutTest", DisplayName = "RoleForPutTest" }; StringContent content = new StringContent(viewModel.ToJsonString(), _encoding, _mediaType);//定義put傳遞的參數、編碼和類型 using var host = await TestHostBuild.GetTestHost().StartAsync();//啓動TestServer var response = await host.GetTestClientWithToken().PostAsync(_testUrl, content);//先添加一個用於更新測試 viewModel.Id = (await response.Content.ReadAsStringAsync()).GetDeserializeObject<ApiResult<ExecuteResult<Role>>>().data.Result.Id; content = new StringContent(viewModel.ToJsonString(), _encoding, _mediaType); //act response = await host.GetTestClientWithToken().PutAsync(_testUrl, content); var result = (await response.Content.ReadAsStringAsync()).GetDeserializeObject<ApiResult<ExecuteResult>>(); //assert Assert.True(result.data.IsSucceed); //測完把添加的刪除 await Delete_Id_ReturnResult(viewModel.Id); } } }
打開測試管理器,運行測試,測試都經過:
項目完成後,以下圖所示