【问题标题】:ViewResult.StatusCode is null despite explicitly setting itViewResult.StatusCode 为 null,尽管已明确设置
【发布时间】:2017-07-14 11:29:10
【问题描述】:

我已经编写了这个控制器方法和这个测试。

控制器方法:

public async Task<IActionResult> Metric(string type, string source)
{
    // Check existence ...

    var model = await _context
        .Metrics
        .FirstAsync(mt => mt.Type == metricType.AsInt() && mt.Source == source);

    Response.StatusCode = HttpStatusCode.OK.AsInt();

    return View(model);
}

测试:

[Fact]
public async Task MetricExistsTest()
{
    // Arrange ...

    // Act
    var result = await _controller.Metric(Metrics.CpuLoad.ToString(), "source-1");

    // Assert
    var viewResult = Assert.IsType<ViewResult>(result);

    Assert.Equal(HttpStatusCode.OK.AsInt(), viewResult.StatusCode.Value);

    var model = Assert.IsAssignableFrom<Metric>(
        viewResult.ViewData.Model
    );
}

现在,问题出在Assert.Equal(HttpStatusCode.OK.AsInt(), viewResult.StatusCode.Value);viewResult.StatusCode 确实是 null。如果我注释掉该行,一切正常。

我做错了什么?为什么是null?我是否正确设置了Response.StatusCode?那么如何验证状态码呢?

谢谢!

【问题讨论】:

  • 从操作中删除 Response.StatusCode = HttpStatusCode.OK.AsInt();。默认响应(在这种情况下是视图)应该有 200 OK
  • @Nkosi 如果我想设置自定义代码,比如 204 No Content,该怎么办?
  • @Nkosi - 终于明白了!看我的回答。并感谢您的帮助!

标签: c# asp.net asp.net-mvc asp.net-core xunit


【解决方案1】:

我终于做到了! 所有帮助我解答和 cmets 的人 - 我非常感谢!

事实证明我有两个问题 - HttpContext 在测试环境中不存在(除非手动设置),Response.StatusCode 没有在结果 ViewResult 对象上设置 StatusCode。 (这些是我的观察,如果我错了,请纠正我)。

问题1解决方案:

设置默认HttpContext 即可解决问题。至少,控制器方法不会因为Response 不再是null 而崩溃。

var controller = new HomeController();

controller.ControllerContext = new ControllerContext();
controller.ControllerContext.HttpContext = new DefaultHttpContext();

问题2解决方案:

事实证明,我需要在 ViewResult 对象上显式设置 StatusCode。出于某种原因,ASP.Core 不会将StatusCodeResponse 对象镜像到结果IActionObject。 (如果我错了,请纠正我)

所以这是解决方案(这是我控制器上的另一种方法,但它清楚地展示了这个想法):

public async Task<IActionResult> Index()
{
    var model = await _context
        .Metrics
        .Where(mt => mt.Type == Metrics.CpuLoad.AsInt())
        .ToListAsync();

    var result = View(model);
    result.StatusCode = (model.Any() ? HttpStatusCode.OK : HttpStatusCode.NoContent).AsInt();

    return result;
}

【讨论】:

  • 请注意,204 响应不应包含正文/视图。 httpstatuses.com/204: "204 响应被标头字段后的第一个空行终止,因为它不能包含消息正文。"
  • @hangy 非常正确。当您的浏览器拒绝加载 204 页面的内容,甚至没有将 URL 添加到历史记录时,请不要感到惊讶。
【解决方案2】:

看起来你应该断言result,而不是viewresult

[Fact]
public async Task MetricExistsTest()
{
    // Arrange ...

    // Act
    var result = await _controller.Metric(Metrics.CpuLoad.ToString(), "source-1");

    // Assert
    var viewResult = Assert.IsType<ViewResult>(result);

    Assert.Equal(HttpStatusCode.OK.AsInt(), result.StatusCode.Value);

    var model = Assert.IsAssignableFrom<Metric>(
        viewResult.ViewData.Model
    );
}

【讨论】:

  • 在我的控制器方法中,Responsenull。你知道为什么吗?以及如何正确设置?
  • 你应该可以模拟 HTTPResonse stackoverflow.com/questions/9823039/…
  • 我能够设置默认响应对象。但是IActionResult仍然没有.StatusCode,所以我不能写result.StatusCode.Value
  • 不幸的是,模拟对我不起作用,但感谢您的回答!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
相关资源
最近更新 更多