我为web api编写了一个动作过滤器。如果api控制器中的方法抛出未处理的异常,则过滤器会创建内部错误500响应。
我需要知道如何测试滤镜?
我已经进行了广泛的研究,但无法创建合适的测试。我尝试了上下文模拟,服务定位器实现,甚至使用测试服务器进行集成测试。
web api控制器如下所示:
namespace Plod.Api.ApiControllers
{
[TypeFilter(typeof(UnhandledErrorFilterAttribute))]
[Route("api/[controller]")]
public class GamesController : BaseApiController
{
public GamesController(IGameService repository,
ILogger<GamesController> logger,
IGameFactory gameFactory
) : base(
repository,
logger,
gameFactory
)
{ }
// ..... controller methods are here
}
}
找到完整的控制器here。
过滤器是:
namespace Plod.Api.Filters
{
public class UnhandledErrorFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.ExceptionHandled = true;
}
}
}
}
我甚至欢迎更改过滤器实现作为可能的解决方法。任何帮助或想法将不胜感激。感谢。
答案 0 :(得分:2)
您可能不会。但是,您可以做的是旋转TestServer
,然后使用HttpClient进行操作。这确实是集成测试,而不是单元测试。但是,这是一种很好的集成测试,因为它可以在管道中安全运行。
此文档说明了如何执行此操作: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1
您将要面对的问题是,您将需要在应用程序内部模拟基础服务。如果不这样做,整个服务器将启动,并尝试访问数据库等。这是一个示例。这是使用最小起订量。顺便说一句,我与单元测试共享ConfigureServices
方法,因此它们使用相同的模拟服务对象网格。您仍然可以使用Moq或NSubstitute的全部功能来测试后端(甚至前端)。
我可以在测试中使用断点击中我的属性。
private void ConfigureServices(IServiceCollection services)
{
var hostBuilder = new WebHostBuilder();
hostBuilder.UseStartup<TestStartup>();
hostBuilder.ConfigureServices(services =>
{
ConfigureServices(services);
});
_testServer = new TestServer(hostBuilder);
_httpClient = _testServer.CreateClient();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_storageManagerFactory.Object);
services.AddSingleton(_blobReferenceManagerMock.Object);
services.AddSingleton(_ipActivitiesLoggerMocker.Object);
services.AddSingleton(_loggerFactoryMock.Object);
services.AddSingleton(_hashingService);
services.AddSingleton(_settingsServiceMock.Object);
services.AddSingleton(_ipActivitiesManager.Object);
services.AddSingleton(_restClientMock.Object);
_serviceProvider = services.BuildServiceProvider();
}
public class TestStartup
{
public void Configure(
IApplicationBuilder app,
ISettingsService settingsService)
{
app.Configure(settingsService.GetSettings());
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var mvc = services.AddMvc(option => option.EnableEndpointRouting = false);
mvc.AddApplicationPart(typeof(BlobController).Assembly);
services.AddSingleton(new Mock<IHttpContextAccessor>().Object);
return services.BuildServiceProvider();
}
}