C# 如何在ASP.NETCore中测试全局错误处理中间件和控制器之间的集成?
我正试图用XUnit编写一些测试,特别是我希望有一个测试,确保当抛出某个异常时,它会被重新映射到一个有意义的错误代码中。 我已经设置了全局错误处理中间件,它工作正常。 下面是我的解决方案工作原理的一些示例代码: 我的控制器有一个post端点,可以返回200或404C# 如何在ASP.NETCore中测试全局错误处理中间件和控制器之间的集成?,c#,asp.net-core,xunit,C#,Asp.net Core,Xunit,我正试图用XUnit编写一些测试,特别是我希望有一个测试,确保当抛出某个异常时,它会被重新映射到一个有意义的错误代码中。 我已经设置了全局错误处理中间件,它工作正常。 下面是我的解决方案工作原理的一些示例代码: 我的控制器有一个post端点,可以返回200或404 //Controller [HttpPost] [ProducesResponseType(200)] [ProducesResponseType(404)] public async Task<StatusCodeResult
//Controller
[HttpPost]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<StatusCodeResult> Create([FromBody] Request request) {
//Process request
handler.Handle(request);
return Ok();
}
//控制器
[HttpPost]
[产品响应类型(200)]
[产品响应类型(404)]
公共异步任务创建([FromBody]请求){
//处理请求
处理(请求);
返回Ok();
}
用于将异常重新映射为错误代码的全局错误处理的中间件
//StartUp Middleware
app.UseExceptionHandler(builder => {
builder.Run(handler: async context => {
IExceptionHandlerFeature error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null) {
int statusCode = (int)GetStatusCodeForException(error.Error);
context.Response.StatusCode = statusCode;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(new ErrorDetails { StatusCode = statusCode, Message = error.Error.Message }.ToString());
}
});
});
//启动中间件
app.UseExceptionHandler(生成器=>{
Run(处理程序:异步上下文=>{
IEExceptionHandlerFeature错误=context.Features.Get();
if(错误!=null){
int statusCode=(int)GetStatusCodeForException(error.error);
context.Response.StatusCode=状态码;
context.Response.ContentType=“应用程序/json”;
wait context.Response.WriteAsync(新的错误详细信息{StatusCode=StatusCode,Message=error.error.Message}.ToString());
}
});
});
然后在测试中,我安排一些模拟,实例化控制器并调用Create方法
//UnitTest
[Fact]
public async Task Test()
{
//Arrange
var mockHandler = new Mock<IHandler>();
mockHandler.Setup(handler => handler.Handle(It.IsAny<Request>())).Throws(new CustomException(It.IsAny<string>()));
MyController myController = new MyController();
//Act
var statusCodeResult = await myController.Create(request);
//Assert
StatusCodeResult result = Assert.IsType<NotFoundResult>(statusCodeResult);
}
//单元测试
[事实]
公共异步任务测试()
{
//安排
var mockHandler=new Mock();
mockHandler.Setup(handler=>handler.Handle(It.IsAny()).Throws(newcustomexception(It.IsAny()));
MyController MyController=新的MyController();
//表演
var statusCodeResult=等待myController.Create(请求);
//断言
StatusCodeResult=Assert.IsType(StatusCodeResult);
}
这里我想确保CustomException被重新映射到404状态代码中。我该怎么做?感谢您的帮助 在您的测试中,中间件不可用。要实现这一点,您需要启动一个托管环境,Microsoft.AspNetCore.TestHost包提供了一个可用于测试的环境:
[事实]
公共异步任务Test1()
{
使用var host=newtestserver(Program.CreateHostBuilder(null));
var client=host.CreateClient();
var requestMessage=newhttprequestmessage(HttpMethod.Get,“/api/controller”);
var result=await client.sendsync(requestMessage);
var status=result.StatusCode;
//TODO:断言
}
现在,当您以引发异常的方式调用API时,应该执行并覆盖中间件。在您的测试中,中间件不可用。要实现这一点,您需要启动一个托管环境,Microsoft.AspNetCore.TestHost包提供了一个可用于测试的环境:
[事实]
公共异步任务Test1()
{
使用var host=newtestserver(Program.CreateHostBuilder(null));
var client=host.CreateClient();
var requestMessage=newhttprequestmessage(HttpMethod.Get,“/api/controller”);
var result=await client.sendsync(requestMessage);
var status=result.StatusCode;
//TODO:断言
}
现在,当您以引发异常的方式调用API时,应该执行并覆盖中间件。您可以使用Microsoft.AspNetCore.Mvc.Testing nuget包中的类。这将在内存中引导应用程序,以允许端到端功能测试。您可以通过HttpClient
进行调用,以确保调用所有中间件等,而不是调用单个操作方法
您使用已在主条目项目中定义的Startup
类,并且可以根据需要将模拟/伪对象添加到IoC容器中。这允许您验证/设置任何依赖项
然后可以将其作为IClassFixture
注入。注入后,在实例上调用.CreateClient()
将返回一个HttpClient
,您可以通过它发出请求
下面是一个示例实现:
// app factory instance
public class TestAppFactory : WebApplicationFactory<Startup>
{
// mock for setup/verify
public Mock<IHandler> MockHandler { get; } = new Mock<IHandler>();
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services =>
{
services.AddSingleton(MockHandler);
});
}
}
public class MyTestClass : IClassFixture<TestAppFactory>
{
private readonly TestAppFactory _factory;
private readonly HttpClient _client;
private readonly Mock<IHandler> _mockHandler;
public MyTestClass(TestAppFactory factory)
{
_factory = factory;
_client = factory.CreateClient();
_mockHandler = factory.MockHandler;
}
[Fact]
public async Task Test()
{
// make calls via _client
}
}
//应用程序工厂实例
公共类TestAppFactory:WebApplicationFactory
{
//用于设置/验证的模拟
公共Mock MockHandler{get;}=new Mock();
受保护的覆盖无效配置WebHost(IWebHostBuilder)
{
builder.ConfigureTestServices(服务=>
{
AddSingleton(MockHandler);
});
}
}
公共类MyTestClass:IClassFixture
{
私有只读TestAppFactory\u工厂;
私有只读HttpClient\u客户端;
私有只读Mock\u mockHandler;
公共MyTestClass(TestAppFactory工厂)
{
_工厂=工厂;
_client=factory.CreateClient();
_mockHandler=factory.mockHandler;
}
[事实]
公共异步任务测试()
{
//通过客户机拨打电话
}
}
您可以使用Microsoft.AspNetCore.Mvc.Testing nuget包中的类。这将在内存中引导应用程序,以允许端到端功能测试。您可以通过HttpClient
进行调用,以确保调用所有中间件等,而不是调用单个操作方法
您使用已在主条目项目中定义的Startup
类,并且可以根据需要将模拟/伪对象添加到IoC容器中。这允许您验证/设置任何依赖项
然后可以将其作为IClassFixture
注入。注入后,在实例上调用.CreateClient()
将返回一个HttpClient
,您可以通过它发出请求
下面是一个示例实现:
// app factory instance
public class TestAppFactory : WebApplicationFactory<Startup>
{
// mock for setup/verify
public Mock<IHandler> MockHandler { get; } = new Mock<IHandler>();
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services =>
{
services.AddSingleton(MockHandler);
});
}
}
public class MyTestClass : IClassFixture<TestAppFactory>
{
private readonly TestAppFactory _factory;
private readonly HttpClient _client;
private readonly Mock<IHandler> _mockHandler;
public MyTestClass(TestAppFactory factory)
{
_factory = factory;
_client = factory.CreateClient();
_mockHandler = factory.MockHandler;
}
[Fact]
public async Task Test()
{
// make calls via _client
}
}
//应用程序工厂实例
公共类TestAppFactory:WebApplicationFactory
{
//用于设置/验证的模拟
公共Mock MockHandler{get;}=new Mock();
受保护的覆盖无效配置WebHost(IWebHostBuilder)
{