4

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!

4
  • 1
    remove Response.StatusCode = HttpStatusCode.OK.AsInt(); from within the action. the default response (in this case the view) should have 200 OK Commented Feb 23, 2017 at 20:28
  • @Nkosi and what if I want to set a custom code, like 204 No Content? Commented Feb 23, 2017 at 20:46
  • There are action results for that learn.microsoft.com/en-us/aspnet/core/mvc/controllers/actions Commented Feb 23, 2017 at 20:48
  • @Nkosi - finally figured it out! See my answer. And thank you for help! Commented Feb 23, 2017 at 22:06

2 Answers 2

3

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; } 
Sign up to request clarification or add additional context in comments.

2 Comments

Note that a 204 response should not have a body/view, though. httpstatuses.com/204: "A 204 response is terminated by the first empty line after the header fields because it cannot contain a message body."
@hangy Very true. Don't get surprised when your browser refuses to load the content of 204 page, or even does not add the URL to history.
0

It looks like you should be Asserting the result, not the 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 ); } 

4 Comments

It turns out that Response is null in my controller method. Do you have an idea why? And how to set it properly?
You should be able to mock the HTTPResonse stackoverflow.com/questions/9823039/…
I was able to set default response object. But still IActionResult does not have .StatusCode, so I cannot write result.StatusCode.Value.
Mocking did not work for me, unfortunately, but thank you for the answer!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.