Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewResult.StatusCode is null despite explicitly setting it

I have written this controller method and this test.

Controller method:

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);
}

Test:

[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
    );
}

Now, the problem is here Assert.Equal(HttpStatusCode.OK.AsInt(), viewResult.StatusCode.Value);. The viewResult.StatusCode is indeed null. If I comment that line out, everything works.

What am I doing wrong? Why is it null? Do I properly set Response.StatusCode? How do I verify status code then?

Thank you!

like image 646
Dmytro Bogatov Avatar asked Sep 17 '25 11:09

Dmytro Bogatov


1 Answers

I finally did it! All those who helped me with answers and comments - I very much appreciate it!

It turns out that I had two problems - HttpContext does not exist (unless set manually) in testing environment and Response.StatusCode does not set StatusCode on resulting ViewResult object. (These are my observations, correct me if I'm wrong).

Problem 1 solution:

As simple as setting default HttpContext solves the problem. At least, controller method does not crash because Response is not null anymore.

var controller = new HomeController();

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

Problem 2 solution:

It turns out that I need to set StatusCode explicitly on ViewResult object. For some reason, ASP.Core does not mirror StatusCode from Response object to resulting IActionObject. (Correct me if I'm wrong)

So here is the solution (it's another method on my controller, but it clearly demonstrates the idea):

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;
}
like image 87
Dmytro Bogatov Avatar answered Sep 20 '25 01:09

Dmytro Bogatov