Mock Azure Function HttpTrigger and Setup Query String - c#

I am working on xUnit for.NET CORE Azure Function that have HttpTrigger. I have managed to mock HttpTrigger that expect to receive data in the body but struggling with Query String. I have made the generic function outside the test class so that it can be used by other Azure Functions tests.
I need help to create mock for HttpRequest that accept query string. I believe need mock that Setup type of IQueryCollection
Azure function
[FunctionName("MyFunction")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "DELETE")] HttpRequest req,
[ServiceBus("MyServiceBus", Connection = "MyServiceBusConn")] IAsyncCollector<Message> servicebusMessage)
{
string sessionId = string.Empty;
var DateTimeNow = DateTime.Now;
sessionId = req.Query["sessions"]; //Mock to return this??
}
Method To Create Mock for HttpRequest Body
public Mock<HttpRequest> CreateMockRequest(object body)
{
var memoryStream = new MemoryStream();
var writer = new StreamWriter(memoryStream);
var json = JsonConvert.SerializeObject(body);
writer.Write(json);
writer.Flush();
memoryStream.Position = 0;
var mockRequest = new Mock<HttpRequest>();
mockRequest.Setup(x => x.Body).Returns(memoryStream);
mockRequest.Setup(x => x.ContentType).Returns("application/json");
return mockRequest;
}
Need help in following method
Method To Create Mock for HttpRequest Query String
public Mock<HttpRequest> CreateQueryMockRequest(object body)
{
var memoryStream = new MemoryStream();
var writer = new StreamWriter(memoryStream);
var json = JsonConvert.SerializeObject(body);
var mockRequest = new Mock<HttpRequest>();
mockRequest.Setup(x => x.Query).Returns(json); // This doesn't work??
mockRequest.Setup(x => x.ContentType).Returns("application/json");
return mockRequest;
}
Test Class
[Fact]
public void Function_ShouldReturn_XYZ()
{
//Arrange
var providerSessionId = RingGoExemptionTestData.GetProviderSession(); //GetProviderSession() implementation below
Mock<HttpRequest> mockHttpRequest = httpResquestFactory.CreateQueryMockRequest(providerSessionId); // this is where I am trying to use method define above
}
Dto Object for Query String
public static RingGoSession GetProviderSession()
{
var ringGoSession = new RingGoSession
{
RingGoRef = "232d3f"
};
return ringGoSession;
}

got the answer;
'Generic Method to deal with Query String`
public Mock<HttpRequest> CreateMockHttpRequest(Dictionary<string, StringValues> query)
{
var context = new DefaultHttpContext();
var request = context.Request;
request.Query = new QueryCollection(query);
var mockRequest = new Mock<HttpRequest>();
mockRequest.Setup(x => x.Query).Returns(request.Query);
return mockRequest;
}
This is how to create Mock by passing Query
var query = new Dictionary<string, StringValues>();
query.TryAdd("myKey", MyKeyValue);
Mock<HttpRequest> mockHttpRequest = httpResquestFactory.CreateMockHttpRequest(query);

You can create a new instance of QueryCollection (read this) and setup the mock.
var mockDict = new Dictionary<string, StringValues>
{
{ "key1", "some value" },
{ "sessions", "random session string"}
};
mockRequest.Setup(x => x.Query).Returns(new QueryCollection(mockDict));

Related

How to unit test multipart/form-data with moq in C#

I have been trying to write a unit test for the method of service which gets multiple/form-data from the Request. Here is my method:
var boundary = MultipartRequestHelper.GetBoundary(
MediaTypeHeaderValue.Parse(HttpContextAccessor.HttpContext.Request.ContentType),
DEFAULT_MULTIPART_BOUNDARY_LENGTH_LIMIT);
var reader = new MultipartReader(boundary, HttpContextAccessor.HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
var streamedFileContent = Array.Empty<byte>();
var dictionary = new Dictionary<string, string>();
while (section != null)
{
var hasContentDispositionHeader =
ContentDispositionHeaderValue.TryParse(
section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
{
streamedFileContent = await FileHelpers.ProcessStreamedFile(
section, contentDisposition, Configuration.GetFileSizeLimit());
}
else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
{
var key = HeaderUtilities
.RemoveQuotes(contentDisposition.Name).Value;
var encoding = GetEncoding(section);
if (encoding == null)
throw new ErrorCodeException("error-invalid-data");
using (var streamReader = new StreamReader(
section.Body,
encoding,
detectEncodingFromByteOrderMarks: true,
bufferSize: 1024,
leaveOpen: true))
{
var value = await streamReader.ReadToEndAsync();
dictionary.Add(key, value);
}
}
}
section = await reader.ReadNextSectionAsync();
}
var file = new File
{
AuthorId = authorStaffId,
Name = dictionary.FirstOrDefault(l => l.Key == "name").Value,
Size = streamedFileContent.Length,
Extension = dictionary.FirstOrDefault(l => l.Key == "extension").Value,
MimeType = dictionary.FirstOrDefault(l => l.Key == "mimeType").Value,
IsTemporary = true,
FileId = Guid.NewGuid()
};
file = await SaveFileContentAsync(streamedFileContent, file);
file.ContentHash = CanculateContentHash(streamedFileContent);
await _fileRepository.AddAsync(file);
Here I am trying to send a request from the Postman and this way it is working fine:
And following way I am trying to test my code with xUnit and Moq:
[Fact]
public async Task UploadFileAsync_WhenFileSizeIsNotBiggerThanLimit_Successful()
{
// Arrange
ConfigureClaims();
ConfigureDatabase();
ConfigureService();
var fakeFileContent = GetFakeFileContent();
var byteContent = Convert.FromBase64String(fakeFileContent);
Stream stream = new MemoryStream(byteContent);
_moqHttpContextAccessor.Setup(x => x.HttpContext.Request.Body).Returns(stream);
_moqHttpContextAccessor.Setup(x => x.HttpContext.Request.ContentType).Returns("multipart/form-data; boundary=----231179732646258011288433");
_moqHttpContextAccessor.Setup(x => x.HttpContext.Request.ContentLength).Returns(0x000000000001d74e);
// Act
var addedFileId = _baseFileService.UploadFileAsync();
var addedFile = _fileRepository.GetById(addedFileId);
// Assert
Assert.NotNull(addedFile);
}
I got the following error message: InvalidDataException: Multipart body length limit 16384 exceeded
And I tried this way:
[Fact]
public async Task UploadFileAsync_WhenFileSizeIsNotBiggerThanLimit_Successful()
{
// Arrange
ConfigureClaims();
ConfigureDatabase();
ConfigureService();
var fakeFileContent = GetFakeFileContent();
var byteContent = Convert.FromBase64String(fakeFileContent);
var byteStringContent = byteContent.ToString();
var forDataDictionary = new Dictionary<string, StringValues>
{
{"file", byteStringContent},
{"name", "test.pdf"},
{"size", "120085"},
{"mimeType", "application/pdf" }
};
var formData = new FormCollection(forDataDictionary);
_moqHttpContextAccessor.Setup(x => x.HttpContext.Request.Form).Returns(formData);
// Act
var addedFileId = _baseFileService.UploadFileAsync();
var addedFile = _fileRepository.GetById(addedFileId);
// Assert
Assert.NotNull(addedFile);
}
I got an error because I am not getting the content from Request.Form. I am getting it from Reques.Body
Then I looked around the Web and could not find any proper answer. What can I do here?
you can take this approach to mock your IformFile.
public static IFormFile AsValidMockIFormFile(this FileInfo physicalFile)
{
var fileMock = new Mock<IFormFile>();
var ms = new MemoryStream();
var writer = new StreamWriter(ms);
writer.Write(physicalFile.OpenRead());
writer.Flush();
ms.Position = 0;
var fileName = physicalFile.Name;
//Setup mock file using info from physical file
fileMock.Setup(_ => _.FileName).Returns(fileName);
fileMock.Setup(_ => _.Length).Returns(ms.Length);
fileMock.Setup(m => m.OpenReadStream()).Returns(ms);
fileMock.Setup(m => m.ContentType).Returns("text/csv");
fileMock.Setup(m => m.ContentDisposition).Returns(string.Format("inline; filename={0}", fileName));
return fileMock.Object;
}
As this above method will give a IformFile object. but to decorate the same you need to pass some data(i.e., you need to hold a sample file in your test data)
var physicalFile = new FileInfo("filePath.txt"); // Put your sample file here
fakeFileContent = FileHelper.AsValidMockIFormFile(physicalFile);
var info=await _controller.UploadAtion(fakeFileContent) as OkObjectResult;

How to write unit test case IHttpClientFactory

I have a method in service layer to connect to a service and i am using IHttpClientFactory. My method is working fine. Now i am trying to write unit test cases for the same.
public async Task<MyObject> MyMethodAsync(string arg1, string arg2)
{
var client = _httpClientFactory.CreateClient("XYZ");
var Authkey = "abc";
var AuthToken = "def";
var headers = new Dictionary<string, string>
{
{ Authkey,AuthToken }
};
client.AddTokenToHeader(headers); //This method set the DefaultRequestheader from the dictionary object
var reqData = new
{
prop1 = "X",
prop2 = "Y"
};//req object
var content = new StringContent(JsonConvert.SerializeObject(reqData), Encoding.UTF8, "application/json");
//This is httpClient Post call for posting data
HttpResponseMessage response = await client.PostAsync("postData", content);
if (!response.IsSuccessStatusCode || response.Content == null)
{
return null;
}
MyObject myObject = JsonConvert.DeserializeObject<MyObject>(response.Content.ReadAsStringAsync().Result);//read the result to an object
return myObject;
}
For the above method i am writing test cases. Here i am trying to set the Post methods out put a status code OK and expecting the
MyMethodAsync method to be true as the PostAsync is true. Here i am getting an exception
System.InvalidOperationException : An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.
[Test]
public async Task MyMethodAsync_Gets_True()
{
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("It worked!")
};
//Mock the httpclientfactory
var _httpMessageHandler = new Mock<HttpMessageHandler>();
var mockFactory = new Mock<IHttpClientFactory>();
//Specify here the http method as post
_httpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK
});
var httpClient = new HttpClient(_httpMessageHandler.Object);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
var arg1 = "X";
var arg2 = "D101";
var service = new MyService(_mockAppSettings.Object, mockFactory.Object);
var result = await service.MyMethodAsync(arg1, arg2);
// Assert
Assert.IsNotNull(result);
}
Can someone show what mistake i am doing here?
As the exception says you have to
either call the PostAsync with an absolute url
or set the BaseAddress of the HttpClient
If you choose the second one all you need to do is this:
var httpClient = new HttpClient(_httpMessageHandler.Object);
httpClient.BaseAddress = new Uri("http://nonexisting.domain"); //New code
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
With this modification the exception will be gone.
But your test will fail because the response.Content will be null and that's why MyMethodAsync will return with null.
To fix this let's change the Setup to this:
public static async Task MyMethodAsync_Gets_True()
{
//Arrange
MyObject resultObject = new MyObject();
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(JsonConvert.SerializeObject(resultObject))
};
var _httpMessageHandler = new Mock<HttpMessageHandler>();
_httpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(response);
...
//Act
var result = await service.MyMethodAsync(arg1, arg2);
//Assert
Assert.NotNull(result);
}

Unit Testing .Net CORE 2.0 WebAPI - Mock (MOQ) HTTP POST with text stream body (not model)

I am trying to unit test my HTTP POST method of my .Net CORE 2.0 API Controller which stream-reads data... Cannot use a "model" type approach as the incoming stream raw data.
Here is the basics of the controller method.
[HttpPost()]
[Authorize(Roles = "contributor")]
public async Task<IActionResult> SubmitReport()
{
IActionResult result = null;
_logger.LogInformation("POST Request");
var buffer = new byte[this.Request.ContentLength.Value];
await this.Request.Body.ReadAsync(buffer, 0, buffer.Length);
string content = System.Text.Encoding.UTF8.GetString(buffer);
// Do something with the 'content'
return (Accepted()); // Assuming all was OK
}
And here's my Unit Test... or rather as far as I can get..
[TestMethod]
public void eFormController_SubmitReport_MockService_ExpectHttpStatusAccepted()
{
var mockContextAccessor = new Mock<IHttpContextAccessor>();
var context = new DefaultHttpContext();
mockContextAccessor.Setup(x => x.HttpContext).Returns(context);
var mockLogger = new Mock<ILogger<object>>();
var ctrl = new Controllers.eFormsController();
var result = ctrl.SubmitReport();
Assert.IsInstanceOfType(result, typeof(Microsoft.AspNetCore.Mvc.AcceptedResult));
}
When I run the test as it stands, the this.Request property is null so how do I Mock a proper HTTP POST request.
Google has yet to yield any favourable results as they all assume a fully defined model, and not a text stream
You have already done most of the work by using the DefaultHttpContext.
Arrange a request that has a body (stream) and the necessary properties to allow the method under test to flow as expected.
Should be able to exercise the test from there
[TestMethod]
public async Task eFormController_SubmitReport_MockService_ExpectHttpStatusAccepted() {
//Arrange
var data = "Hello World!!";
var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(data));
var httpContext = new DefaultHttpContext();
httpContext.Request.Body = stream;
httpContext.Request.ContentLength = stream.Length;
var mockLogger = new Mock<ILogger<object>>();
var controllerContext = new ControllerContext() {
HttpContext = httpContext,
};
var controller = new Controllers.eFormsController(mockLogger.Object) {
ControllerContext = controllerContext,
};
//Act
var result = await controller.SubmitReport();
//Assert
Assert.IsInstanceOfType(result, typeof(Microsoft.AspNetCore.Mvc.AcceptedResult));
}

How to create mock HTTP post request with a JSON body using Moq

I'm trying to do basically what the title says in order to unit test my api controller, but I have problems finding the proper way and can't afford spending too much time on this. Here is my code.
[TestMethod]
public void Should_return_a_valid_json_result()
{
// Arrange
Search search = new Search();
search.Area = "test";
string json = JsonConvert.SerializeObject(search);
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
request.Setup(r => r.HttpMethod).Returns("POST");
request.Setup(r => r.InputStream.ToString()).Returns(json);
context.Setup(c => c.Request).Returns(request.Object);
var controller = new UserController();
controller.ControllerContext = new HttpControllerContext() { RequestContext = context };
//more code
}
Last line returns Error CS0029 Cannot implicitly convert type
'Moq.Mock System.Web.HttpContextBase' to
'System.Web.Http.Controllers.HttpRequestContext'.
I am also not sure about the Moq syntax I should use, other questions,examples and Moq Documentation didn't help me much.
I'm using this approach
var json = JsonConvert.SerializeObject(request);
var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
var httpContext = new DefaultHttpContext()
{
Request = { Body = stream, ContentLength = stream.Length }
};
var controllerContext = new ControllerContext { HttpContext = httpContext };
var controller = new Your_Controller(logic, logger) { ControllerContext = controllerContext };
No need for mock here if the intention is just to pass a request.
[TestMethod]
public void Should_return_a_valid_json_result() {
// Arrange
var search = new Search();
search.Area = "test";
var json = JsonConvert.SerializeObject(search);
var request = new HttpRequestMessage();
request.Method = HttpMethod.Post;
request.Content = new StringContent(json);
var controller = new UserController();
controller.Request = request;
//more code
}

How to fix Windows.UI.xaml.RoutedEventArgs exception?

public async static Task<RootObject> GetWeather(string username, string password)
{
var http = new HttpClient();
var response = await http.GetAsync(postURI);
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var datax = (RootObject)serializer.ReadObject(ms);
return datax;
}
I have the necessary models ready and I made the function call with some hard-coded data to test but its not working.

Categories

Resources