[英]How do I test the integration between the Global error handling middleware and my controller in ASP.Net Core?
I'm trying to write some test with XUnit, specifically I'd like to have a test that ensures that when a certain exception is thrown it gets remapped into a meaningful error code.我正在尝试用 XUnit 编写一些测试,特别是我想要一个测试,以确保当某个异常被抛出时,它会被重新映射到一个有意义的错误代码中。 I already set up the Global error handling middleware and it works correctly.我已经设置了全局错误处理中间件,它可以正常工作。 Here there is some example code of how my solution works:这里有一些关于我的解决方案如何工作的示例代码:
My controller with a post endpoint that can return 200 or 404我的 controller 带有可以返回 200 或 404 的后端点
//Controller
[HttpPost]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<StatusCodeResult> Create([FromBody] Request request) {
//Process request
handler.Handle(request);
return Ok();
}
The Middleware for the Global error handling that remaps exceptions into Error codes用于将异常重新映射为错误代码的全局错误处理中间件
//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());
}
});
});
And then my test in where I arrange some mocks, instantiate the controller and call the Create method然后在我安排一些模拟的地方进行测试,实例化 controller 并调用 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);
}
Here I want to ensure that the CustomException is remapped into a 404 status code.在这里,我要确保将 CustomException 重新映射为 404 状态代码。 How do I do it?我该怎么做? Any help is appreciated.任何帮助表示赞赏。
In your test the middleware is not available.在您的测试中,中间件不可用。 You need to spin up a hosting environment to do that, the package Microsoft.AspNetCore.TestHost
provides you with one that you can use for testing:您需要启动一个托管环境来执行此操作,package Microsoft.AspNetCore.TestHost
为您提供了一个可用于测试的环境:
[Fact]
public async Task Test1()
{
using var host = new TestServer(Program.CreateHostBuilder(null));
var client = host.CreateClient();
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/controller");
var result = await client.SendAsync(requestMessage);
var status = result.StatusCode;
// TODO: assertions
}
Now when you call your API in a way an exception is thrown, the middleware should be executed and covered.现在,当您以引发异常的方式调用 API 时,应该执行并覆盖中间件。
You can use the WebApplicationFactory
class from the Microsoft.AspNetCore.Mvc.Testing nuget package.您可以使用 Microsoft.AspNetCore.Mvc.Testing nuget package 中的WebApplicationFactory
class。 This bootstraps your application in-memory to allow for end to end functional tests.这会在内存中引导您的应用程序,以允许进行端到端的功能测试。 Rather than calling individual action methods you can make calls via HttpClient
to ensure all middleware etc is called.您可以通过HttpClient
进行调用,而不是调用单独的操作方法,以确保调用所有中间件等。
You use the Startup
class that you have already defined in your main entry project and can add mock/fake objects to the IoC container as required.您使用已在主入口项目中定义的Startup
class 并可以根据需要将模拟/伪造对象添加到 IoC 容器。 This allows you to verify/setup any dependencies.这允许您验证/设置任何依赖项。
You can then inject this as an IClassFixture
.然后,您可以将其作为IClassFixture
注入。 Once injected calling .CreateClient()
on the instance will return an HttpClient
, through which you can make requests.一旦在实例上注入调用.CreateClient()
将返回一个HttpClient
,您可以通过它发出请求。
Here is an example implementation:这是一个示例实现:
// 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
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.