.net 如何让我的C#测试服务器故意抛出异常?

xlpyo6sf  于 2023-04-13  发布在  .NET
关注(0)|答案(2)|浏览(130)

我有一个ErrorHandlingMiddleware类,它跨多个项目使用,因此存在于一个共享库中(而不是在API中),我想为它编写一些测试。我已经使用TestServer编写了一个通过测试的代码(如this article中所述),这证明了当端点没有抛出异常时,我的中间件可以工作,但是我在研究如何故意引发异常以触发错误处理部分时遇到了麻烦。
我在这上面找到的唯一一件事是this question,它与我想要的正好相反。
这是我的中间件代码- ErrorHandlingService,它可以很好地处理和格式化我的所有错误。

public ErrorHandlingMiddleware(RequestDelegate next, IErrorHandlingService errHandler)
        {
            _next = next;
            _errHandler = errHandler;
        }

        public async Task Invoke(HttpContext context, IHostEnvironment env)
        {
            try
            {
                _errHandler.AddRequestInformation(Guid.NewGuid(), DateTime.Now, $"{context.Request.Method} {context.Request.Path}");

                await _next(context);
            }
            catch (Exception ex)
            {
                _errHandler.AddError(new MyError()
                {
                    Title = "An unknown error occurred during execution",
                    ErrorID = "---",
                    ErrorMessage = env.IsProduction() ? "" : ex.ToString(),
                    HttpCode = HttpStatusCode.InternalServerError
                });

                context.Response.StatusCode = (int)_errHandler.ErrorResponse.StatusCode;

                await context.Response.WriteAsJsonAsync(_errHandler.ErrorResponse);
            }
        }

以及测试是否抛出“无”异常的通过测试。

public class ErrorHandlingMiddlewareTests
    {
        private async Task<IHost> GetHost()
        {
            return await new HostBuilder()
                .ConfigureWebHost(webBuilder =>
                {
                    webBuilder
                        .UseTestServer()
                        .ConfigureServices(services =>
                        {
                            services.Add(ServiceDescriptor.Scoped<IErrorHandlingService, ErrorHandlingService>());
                        })
                        .Configure(app =>
                        {
                            app.UseMiddleware<ErrorHandlingMiddleware>();
                        });
                })
                .StartAsync();
        }

        [Fact]
        public async Task NewRequest_AddsRequestInformation()
        {
            // Arrange
            using var host = await GetHost();
            var requestRoute = "/route/to/endpoint";

            var server = host.GetTestServer();
            server.BaseAddress = new Uri("https://example.com/");

            // Act
            var context = await server.SendAsync(c => //throws a 404, I'm not testing for that
            {
                c.Request.Method = HttpMethods.Get;
                c.Request.Path = requestRoute;
            });

            // Assert
            var errorResponse = host.Services.GetService<IErrorHandlingService>().ErrorResponse;
            errorResponse.ErrorContent.Request.Should().Be("GET " + requestRoute);
            errorResponse.ErrorContent.TraceID.Should().NotBeEmpty();
        }
    }

那么,现在如何让测试服务器抛出一个可以被中间件捕获的异常呢?

qyzbxkaa

qyzbxkaa1#

好吧,不到24小时后,我解决了这个问题,结果和往常一样,我只需要睡一觉就可以了。StripingWarrior的评论将我引向了一个guide,虽然没有说任何我不知道的事情,但确实促使我思考一个应用程序实际上是如何在.NET中构建的,以及一个普通的API将在哪里寻找控制器/路由。
长话短说,经过一些试验和错误,以及对Startup.cs如何工作的一些研究和一些routing basics,这里是我如何解决的:

private async Task<IHost> GetHost()
        {
            return await new HostBuilder()
                .ConfigureWebHost(webBuilder =>
                {
                    webBuilder
                        .UseTestServer()
                        .ConfigureServices(services =>
                        {
                            services.AddRouting(); // <- new line
                            services.Add(ServiceDescriptor.Scoped<IErrorHandlingService, ErrorHandlingService>());
                        })
                        .Configure(app =>
                        {
                            app.UseRouting(); // <- new line
                            app.UseMiddleware<ErrorHandlingMiddleware>();
                            app.UseEndpoints(endpoints => // <- new section
                            {
                                endpoints.MapGet("/hello", () => "Hello World!");
                                endpoints.MapGet("/err", () => { throw new Exception(); });
                            });
                        });
                })
                .StartAsync();
        }

使用一些新端点的内联定义意味着我可以轻松地控制进出的内容,并且如果需要的话,可能会使响应变得更加复杂。我想你很少使用本地TestServer在类库中测试东西,但我希望这对下一个没有Startup类的人有帮助。

a8jjtwal

a8jjtwal2#

一种方法是用一个标志重载处理程序,并将其 Package 在DEBUG中,这样它就不会出现在生产构建中。

#if DEBUG
public async Task Invoke(HttpContext context, IHostEnvironment env, isErrorTest)
{
  if (isErrorTest)
  {
    // Either build and respond with your error here, or possibly set something up on the server that would cause the normal handler to throw the error you want
    _errHandler.AddError(new MyError()
    {
      // ...
    });
    // ... error response
  }

  // if not error test, call your normal handler
}
#endif

相关问题