如何在asp.net核心中为web api单元测试动作过滤器属性?

时间:2017-10-05 01:28:56

标签: asp.net-core-mvc actionfilterattribute

我为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;
            }
        }
    }
}

我甚至欢迎更改过滤器实现作为可能的解决方法。任何帮助或想法将不胜感激。感谢。

1 个答案:

答案 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();
    }
}