Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test a Controller action using the Response property in ASP.NET 5 (MVC 6)? [duplicate]

In an ASP.NET Core 1.0 (MVC 6) project I have a Controller action method in which I use the Response property to set a header:

[HttpGet]
public IActionResult Get()
{
    ...

    Response.Headers.Add("Location", location);

    ...
}

I tried to implement a unit test for this action method, but the value of the Response property is null.

This was easy to solve in the previous versions of ASP.NET, because the Response property had a setter, and you could simply set its value to a new HttpResponse instance during a unit test.

But in ASP.NET 5 Response does not have a setter, only a getter.
How can I set a value for Response in a unit test?

UPDATE: Just to make clear: this question is about ASP.NET Core 1.0. The other question linked as duplicate is about ASP.NET 4, and the Api changed since then so the answer there does not apply to this question.

like image 603
Mark Vincze Avatar asked Feb 10 '16 15:02

Mark Vincze


People also ask

How do you write a unit test for a controller?

Writing a Unit Test for REST Controller First, we need to create Abstract class file used to create web application context by using MockMvc and define the mapToJson() and mapFromJson() methods to convert the Java object into JSON string and convert the JSON string into Java object.

What are controllers and actions in MVC?

A controller action returns something called an action result. An action result is what a controller action returns in response to a browser request. The ASP.NET MVC framework supports several types of action results including: ViewResult - Represents HTML and markup.


1 Answers

I found one solution to the problem, however, it's a bit tedious and convoluted, so I'm still interested in seeing a simpler approach, if any exists.

The Controller gets the value of its Response property from ActionContext.HttpContext. What makes mocking this difficult is that all these properties are read-only, so we cannot just simply set a mock value, we have to create mocks for every object in play.

The part of the Response I needed in my test was the Headers collection, so I had to create and use the following mocks to make that availale. (Mocking is done with Moq.)

var sut = new MyController();

// The HeaderDictionary is needed for adding HTTP headers to the response.
// This needs a couple of different Mocks, because many properties in the class model are read-only.
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);

sut.ActionContext = new ActionContext()
{
    HttpContext = httpContext.Object
};

This is a bit more code than what I'd like to see to mock a single property, but I couldn't find any better approach yet, and it seems to be working nicely.

like image 168
Mark Vincze Avatar answered Oct 16 '22 09:10

Mark Vincze