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

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 the header:

 [HttpGet] public IActionResult Get() { ... Response.Headers.Add("Location", location); ... } 

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

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

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

UPDATE : just to be clear: this question is about ASP.NET Core 1.0 . Another duplicate related question is about ASP.NET 4, and Api has changed since then, so the answer to this question is not applicable.

+6
source share
2 answers

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

Controller gets the value of its Response property from ActionContext.HttpContext . What complicates this is that all of these properties are read-only, so we just cannot just set the mock value, we must create mocks for every object in the game.

Part of the answer I needed in my test was in the Headers collection, so I had to create and use the following layouts to do this. (The deal is executed using 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 would like to see to mock one property, but have not yet found a better approach, and it seems to work well.

+10
source

You can use ResponseWrapper with virtual properties, and you can mock it and wait for one call to the AddHeader virtual method with the Location parameter. Relevant question here: MOQ - Refusing the response of the controller MVC.Cookies.Clear ()

You can check these examples: for ASP.Net 5 MVC 6:

Another option if you want to try NancyFx ( http://nancyfx.org/ ) ( https://github.com/NancyFx/Nancy ): https://github.com/NancyFx/Nancy/wiki/Testing-your -application

For example, if you tested the login page and wanted to verify that the user was redirected to the "error" page, if they entered incorrect credentials, which you could use in the ShouldHaveRedirectedTo statement:

 [Fact] public void Should_redirect_to_login_with_error_details_incorrect() { // Given var bootstrapper = new DefaultNancyBootstrapper(); var browser = new Browser(bootstrapper); // When var response = browser.Post("/login/", (with) => { with.HttpRequest(); with.FormValue("Username", "username"); with.FormValue("Password", "wrongpassword"); }); // Then response.ShouldHaveRedirectedTo("/login?error=true&username=username"); 

}

There are more:

 [Fact] public void Should_display_error_message_when_error_passed() { // Given var bootstrapper = new DefaultNancyBootstrapper(); var browser = new Browser(bootstrapper); // When var response = browser.Get("/login", (with) => { with.HttpRequest(); with.Query("error", "true"); }); // Then response.Body["#errorBox"] .ShouldExistOnce() .And.ShouldBeOfClass("floatingError") .And.ShouldContain( "invalid", StringComparison.InvariantCultureIgnoreCase); } 
0
source

All Articles