For most of the recent projects I have been involved, there was always a dependency consumed via an HTTP call. These were downstream services, other microservices or 3rd party systems. Depending on the architecture and code flow, I have seen a huge need for mocking HttpRequest
starting from unit tests to all the way to integration tests. After trying different options so far, I ended up using the following flow and happy to share for those of you dealing with similar things.
HttpRequest Body
Most probably this is something action as the main input to your business logic somewhere either at Controller
or maybe somewhere at service layer. Regardless of the case, I found the following method of mocking the most effective and flexible.
public class HttpRequestTests
{
private MemoryStream _memoryStream;
private Mock<HttpRequest> _mockRequest;
[TestInitialize]
public void Init()
{
_mockRequest = CreateMockRequest(new TestBodyData());
}
[TestCleanup]
public void Cleanup()
{
_memoryStream.Dispose();
}
private Mock<HttpRequest> CreateMockRequest(object body)
{
var json = JsonConvert.SerializeObject(body);
var byteArray = Encoding.ASCII.GetBytes(json);
_memoryStream = new MemoryStream(byteArray);
_memoryStream.Flush();
_memoryStream.Position = 0;
var mockRequest = new Mock<HttpRequest>();
mockRequest.Setup(x => x.Body).Returns(_memoryStream);
return mockRequest;
}
}
As seen from the code, we are converting a simple DTO into a JSON string and writing it to MemoryStream
at test initialization. During the test cleanup, we are releasing it from the memory so other tests can run in isolation. This gives an opportunity to fill in the body with any type of data you need.
Typically MemoryStream
is used as part of using(var ms = MemoryStream(byteArray)
but doing this way disposes the stream after program flow exits Init
function and gives us runtime exception. This is why MemoryStream
is only disposed at the cleanup. This was a tiny detail but led me spend a couple good minutes to realise…
HttpRequest Query Parameters
This has taken for me to get to the bottom of it after reading some posts and how Microsoft teams implemented at large, i.e. Github. Micorosft Docs came to the rescue and I ended up mocking the query parameters of the request like below.
private MockQueryParameters(string param1, string param2)
{
var paramsDictionary = new Dictionary<string, StringValues>
{
{ "param1", param1 },
{ "param2", param2 }
};
_mockRequest.Setup(i => i.Query).Returns(new QueryCollection(paramsDictionary));
}
This code assumes that you access to query string params using a pattern like var param1= request.Query["param1"];
.
I hope you find these bits useful for your tests going forward. I also see in the future if there are breaking changes, I’ll try to update these samples. However, I believe these classes are so much crucial to Http
layer in the ecosystem so it is less likely to have a dramatic change in the usage.
Full code
public class HttpRequestTests
{
private MemoryStream _memoryStream;
private Mock<HttpRequest> _mockRequest;
[TestInitialize]
public void Init()
{
_mockRequest = CreateMockRequest(new TestBodyData());
MockQueryParameters("test1", "test2");
}
[TestCleanup]
public void Cleanup()
{
_memoryStream.Dispose();
}
private Mock<HttpRequest> CreateMockRequest(object body)
{
var json = JsonConvert.SerializeObject(body);
var byteArray = Encoding.ASCII.GetBytes(json);
_memoryStream = new MemoryStream(byteArray);
_memoryStream.Flush();
_memoryStream.Position = 0;
var mockRequest = new Mock<HttpRequest>();
mockRequest.Setup(x => x.Body).Returns(_memoryStream);
return mockRequest;
}
private MockQueryParameters(string param1, string param2)
{
var paramsDictionary = new Dictionary<string, StringValues>
{
{ "param1", param1 },
{ "param2", param2 }
};
_mockRequest.Setup(i => i.Query).Returns(new QueryCollection(paramsDictionary));
}
}
What do you think?