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:
- 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.
- Create Dictionary<string,StringValues> for query parameters. Add query parameter name and instance of StringValues to dictionary. Repeat it for all query parameters.
- 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.
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.
Pingback:The Morning Brew - Chris Alcock » The Morning Brew #2956
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”);`
how you’re able to setup the `_controller` so that you can run `_controller.Request.QueryString = new QueryString(“?showhtml=1&showdoc=0”);’ ??