Using query strings in ASP.NET Core unit tests

Using query string in controller unit tests is actually easy until we don’t need anything more advanced. We can buld up a string with query parameters and go with it. But what if things get more complex and we need encoding or multiple values? Here’s how to build safe query string for ASP.NET COre controller unit tests.

NB! It is recommended to use action method arguments instead of request query parameters in your controllers. If you have good reason to work with query strings directly then this post will help you.

Let’s start with quick’n’dirty example where query string is hardcoded.

[Fact]
public async Task ViewPdf_returns_view_if_application_exists_and_html_was_asked()
{
    var model = new ApplicationReviewModel();
    _controller.Request.QueryString = new QueryString("?showhtml=1&showdoc=0");
   
    _applicationServiceMock.Setup(a => a.GetDocumentReview(It.IsAny<Guid>(), It.IsAny<string>()))
                           .ReturnsAsync(() => model);

    var result = await _controller.ViewPdf(Guid.NewGuid()) as ViewResult;

    Assert.Same(model, result.Model);
    Assert.Equal("ApplicationPdf", result.ViewName);
}

But what if we don’t have primitive query strings and we don’t want to take care of formatting and encoding of query parameters?

Building query string using QueryCollection

To build more complex query strings we can use QueryCollection class. It’s a little bit unconveniet beast but it has everything we need to build up query strings from values we have.

Building query string using QueryCollection class needs three steps:

  1. Create instance of StringValues class. It’s a class that takes either string or array of strings to its constructor. This class holds values for query string parameter.
  2. Create Dictionary<string,StringValues> for query parameters. Add query parameter name and instance of StringValues to dictionary. Repeat it for all query parameters.
  3. Create instance of QueryCollection and use dictionary as contructor argument.

Here’s one unit test to illustrate building of query string using StringValues, dictionary and QueryCollection. Notice QueryCollection is assigned to Query property of Request.

[Fact]
public async Task ViewPdf_returns_view_if_document_exists_and_html_was_asked()
{
    var model = new ApplicationReviewModel();
    var dictionary = new Dictionary<string, StringValues>();
    dictionary.Add("showhtml", new StringValues("1"));
    dictionary.Add("showtoc", new StringValues("0"));

    _controller.Request.Query = new QueryCollection(dictionary);
   
    _applicationServiceMock.Setup(a => a.GetDocumentReview(It.IsAny<Guid>(), It.IsAny<string>()))
                           .ReturnsAsync(() => model);

    var result = await _controller.ViewPdf(Guid.NewGuid()) as ViewResult;

    Assert.Same(model, result.Model);
    Assert.Equal("ApplicationPdf", result.ViewName);
}

Let’s modify this test a little bit and add query parameter with multiple values.

[Fact]
public async Task ViewPdf_returns_view_if_document_exists_and_html_was_asked()
{
    var model = new ApplicationReviewModel();
    var dictionary = new Dictionary<string, StringValues>();
    dictionary.Add("showhtml", new StringValues("1"));
    dictionary.Add("showtoc", new StringValues("0"));
    dictionary.Add("showpages", new StringValues(new[] { "1", "3" }));

    _controller.Request.Query = new QueryCollection(dictionary);
   
    _applicationServiceMock.Setup(a => a.GetDocumentReview(It.IsAny<Guid>(), It.IsAny<string>()))
                           .ReturnsAsync(() => model);

    var result = await _controller.ViewPdf(Guid.NewGuid()) as ViewResult;

    Assert.Same(model, result.Model);
    Assert.Equal("ApplicationPdf", result.ViewName);
}

Here’s the resulting query string in red box.

Multi-valued query string parameter in ASP.NET Core unit test

If query parameter has value that needs encoding then encoding is done automatically. We don’t have to worry about it. We just add parameters and their values and ASP.NET Core takes care of everything else.

Wrapping up

When unit testing ASP.NET Core controller actions that read query strings from request we can use QueryString class. It’s easy but we have to provide strictly correct query string. When using StringValues, dictionary and QueryCollection class we have to write more code. Luckily we don’t have to write ugly or too long code and all dirty work on building the final query string is done by ASP.NET Core.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    3 thoughts on “Using query strings in ASP.NET Core unit tests

    • Pingback:The Morning Brew - Chris Alcock » The Morning Brew #2956

    • February 21, 2022 at 10:10 pm
      Permalink

      Really interesting post. I’m curious how you’re able to setup the `_controller` so that you can run `_controller.Request.QueryString = new QueryString(“?showhtml=1&showdoc=0”);`

    • October 10, 2022 at 10:26 pm
      Permalink

      how you’re able to setup the `_controller` so that you can run `_controller.Request.QueryString = new QueryString(“?showhtml=1&showdoc=0”);’ ??

    Leave a Reply

    Your email address will not be published. Required fields are marked *