.NET6之MiniAPI(二十九):UnitTest
MiniAPI的单元测试与asp.net web api的单元测试大体是相同的(毕竟都是asp.net core),只是在小细节上有一些差异,文章中会说到这点。
本文测试框架是XUnit,Mock框架是Moq,关于这两个框架和库的学习,这里就忽略了。
首先创建两个项目,API项目MiniAPI19UnitTest,UnitTest项目MiniAPI19UnitTestUT,如下:
MiniAPI19UnitTest
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IOrderService, OrderService>();
var app = builder.Build();
app.MapGet("/order", (IOrderService orderService) =>
{
return "Result:" + orderService.GetOrder("123");
});
app.MapPost("/order", (Order order, IOrderService orderService) =>
{
return "Result:" + orderService.AddOrder(order);
});
app.Run();
public interface IOrderService
{
bool AddOrder(Order order);
string GetOrder(string orderNo);
}
public class OrderService : IOrderService
{
private readonly ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger)
{
_logger = logger;
}
public string GetOrder(string orderNo)
{
return "this is my order,orderno:" + orderNo;
}
public bool AddOrder(Order order)
{
_logger.LogInformation(order.ToString());
return true;
}
}
public record Order
{
public string OrderNo { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
MiniAPI19UnitTestUT:在本项目中添加引用MiniAPI19UnitTest项目
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Moq;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
namespace MiniAPI19UnitTestUT
{
public class MiniAPI19Test
{
[Fact]//无参测试
public async Task GetOrderTest()
{
var orderNo = "abcd";
//用Moq来mock server接口,达到层的隔离
var mock = new Mock<IOrderService>();
mock.Setup(x => x.GetOrder(It.IsAny<string>())).Returns(orderNo);
var myapp = new MyAppHostTest(services => services.AddSingleton(mock.Object));
var client = myapp.CreateClient();
var result = await client.GetStringAsync("/order");
Assert.Equal($"Result:{orderNo}", result);
}
[Theory]//有参测试
[InlineData(true)]
[InlineData(false)]
public async Task PostOrderTest(bool backResult)
{
var mock = new Mock<IOrderService>();
mock.Setup(x => x.AddOrder(It.IsAny<Order>())).Returns(backResult);
var myapp = new MyAppHostTest(services => services.AddSingleton(mock.Object));
var client = myapp.CreateClient();
var content = new StringContent(System.Text.Json.JsonSerializer.Serialize(new Order{OrderNo = "abcd",Name = "Surface Pro 8",Price = 10000}),System.Text.Encoding.UTF8,"application/json");
var response = await client.PostAsync("/order", content);
var result = await response.Content.ReadAsStringAsync();
Assert.Equal($"Result:{backResult}", result);
}
}
//本类是加构我们MiniAPI web host的类型,封装后以供测试程序调用
class MyAppHostTest : WebApplicationFactory<Program>
{
private readonly Action<IServiceCollection> _services;
public MyAppHostTest(Action<IServiceCollection> services)
{
_services = services;
}
protected override IHost CreateHost(IHostBuilder builder)
{
builder.ConfigureServices(_services);
return base.CreateHost(builder);
}
}
}
上面的代码会报错,找不到Program的,这是因为API项目是用Top Level的方式来开发的,Program的访问修饰符是internal,虽然添加引用了MiniAPI19UnitTest项目,但Program是访问不到的,这里有两个解决方案,要么不用Top Level,如下面这样写代码:
public class Program
{
static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IOrderService, OrderService>();
var app = builder.Build();
app.MapGet("/test", (IOrderService orderService) =>
{
return "Result:" + orderService.GetOrder("123");
});
app.Run();
}
}
或者在MiniAPI19UnitTest.csproj文件中添加如下配置,让测试项目能访问到Program
<ItemGroup>
<InternalsVisibleTo Include="MiniAPI19UnitTestUT"/>
</ItemGroup>
用反射工具查看API项目结果如下,Main函数是Top-Level Entry Point方式,也看不到Program
这时,就可以开心地写自己的单元测试了。
想要更快更方便的了解相关知识,可以关注微信公众号
****欢迎关注我的asp.net core系统课程****
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524