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

℡╲_俬逩灬. 提交于 2020-05-12 11:32:09

问题


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.


回答1:


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.




回答2:


You can use a ResponseWrapper with virtual properties and you can mock it and expect one call for virtual AddHeader method with "Location" parameter. Relevant Question Here: MOQ - Mocking MVC Controller's Response.Cookies.Clear()

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

  • http://www.jerriepelser.com/blog/unit-testing-controllers-aspnet5
  • http://dotnetthoughts.net/creating-unit-tests-for-asp-net-mvc-6-applications/

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

For example - if you were testing a login page and wanted to verify that the user was redirected to an “error” page if they entered incorrect credentials you could use the ShouldHaveRedirectedTo assertion:

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


来源:https://stackoverflow.com/questions/35319501/how-to-unit-test-a-controller-action-using-the-response-property-in-asp-net-5-m

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!