在动作内部分配响应 属性 时对控制器动作进行单元测试

Unit testing Controller Action when Response property is assigned inside of an action

我在此 中看到了完全相同的问题,但 none 的解决方案现在可以在 ASP.Net Core 2.2 中使用。当我调试单元测试时,响应 属性 仍然为空,因此测试失败。 我一直在阅读 asp.net 核心文档以获取如何模拟 ControllerContext 以便响应 属性 具有值的答案,但我找不到任何有效的方法。

下面是动作里面惹麻烦的那一行:

Response.Headers.Add("Access-Control-Expose-Headers", "Content-Range");

所以我在单元测试设置中得到的结果是:

        var routeData = new RouteData();
        routeData.Values.Add("controller", "Home");

        var headerDictionary = new HeaderDictionary();
        var response = new Mock<HttpResponse>();
        response.SetupGet(r => r.Headers).Returns(headerDictionary);

        var httpContext = new Mock<HttpContext>();
        httpContext.SetupGet(a => a.Response).Returns(response.Object);

        var actionContext = new ActionContext(
            httpContext.Object,
            routeData, 
            new ControllerActionDescriptor());

        _controller.ControllerContext = new ControllerContext(actionContext);

许多设置可以通过使用 DefaultHttpContext 来避免,因为 DefaultHttpContext 已经填充了所需的属性。这包括 Response 及其成员

//..

var routeData = new RouteData();
routeData.Values.Add("controller", "Home");

var httpContext = DefaultHttpContext(); //<--

var actionContext = new ActionContext(
    httpContext,
    routeData, 
    new ControllerActionDescriptor());

_controller.ControllerContext = new ControllerContext(actionContext);

//...

在测试被测对象后,可以从控制器使用的上下文中获得响应并断言所需的行为。

//...

//Assert
var response = httpContext.Response;
var key = "Access-Control-Expose-Headers";
Assert.True(response.Headers.TryGetValues(key, out var value));
Assert.Equals("Content-Range", value.FirstOrDefault()

最后,我成功地使用以下代码模拟了 ControllerHttpContext

    protected void SetUpControllerContext(ClaimsPrincipal principal)
    {
        var headerDictionary = new HeaderDictionary();
        var response = new Mock<HttpResponse>();
        response.SetupGet(r => r.Headers).Returns(headerDictionary);

        var httpContext = new Mock<HttpContext>();
        httpContext.SetupGet(a => a.Response).Returns(response.Object);
        httpContext.SetupGet(a => a.User).Returns(principal);


        this.SutController.ControllerContext = new ControllerContext()
        {
            HttpContext = httpContext.Object
        };
    }

现在允许在 Controller 的操作中更改 Response 属性,并且不会触发错误。