How to mock ConfigurationManager.ConnectionStrings with moq in Unit Test case project? - c#

I am writing a unit test cases fro Azure function.In my function app configuration section i have added my connection string.
When the azure function runs in azure below line of code is working fine.
var connStr = ConfigurationManager.ConnectionStrings["SqlConnection"].ConnectionString;
If i am calling the azure function from unit test case this line is throwing exception.
"object reference not set to an instance of an object".
Form unit test case how i can execute this line of code.(using Moq).
Test Method :
[TestMethod]
public async Task GetDataFromAzureSQL_Test()
{
var req = new HttpRequestMessage();
var obj = new Modeltest
{
id = 1,
name ="",
location=""
};
var content = new StringContent(JsonConvert.SerializeObject(obj).ToString(), Encoding.UTF8, "application/json");
req.Content = content;
var result = await Function.Function1.Run(req, new Mock<ILogger>().Object);
Assert.IsTrue("OK" == result.StatusCode.ToString());
}

Related

Unit Test in Azure Function C#

I want to unit test my azure function API by sending mock request and response data. But my test is getting failed even if i pass same Json data on both request and response.
TestCode
[TestMethod]
public async Task ClinicReadTestMethod()
{
//Arrange
//var clinicRequest = new
//{
// Id = "1",
// OpenIdProvider = "Google",
// Subject = "Test",
// Name = "Test",
// Address = "Test",
// Email = "Test",
// Phone = "Test",
// Notes = "Test"
//};
var query = new Dictionary<string, StringValues>();
query.Add("openIdProvider", "Google");
query.Add("subject", "Test");
//var body = JsonSerializer.Serialize(clinicRequest);
var logger = Mock.Of<ILogger>();
var client = Mock.Of<CosmosClient>();
ContentResultFactory contentResultFactory = new ContentResultFactory();
//Act
var testFunction = new ClinicReadFunction(contentResultFactory);
var result = await testFunction.Run(TestFactory.HttpRequestSetup(query), client, logger); //fixme
var resultObject = JsonSerializer.Serialize(result as ContentResult);
//Assert
var clinicResponse = new
{
Id = "1",
openIdProvider = "Google",
subject = "Test",
Name = "Test",
Address = "Test",
Email = "Test",
Phone = "Test",
Notes = "Test"
};
var resultBody = JsonSerializer.Serialize(clinicResponse);
//var res = contentResultFactory.CreateContentResult(HttpStatusCode.OK);
Assert.AreEqual(resultBody, resultObject);
}
}
This is how my azure function looks like. It is taking two parameters and returning the response. I have tried to mock the data for unit test still no success. If anyone have idea how to unit test this azure function please let me know.
//AzureFunction
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "")] HttpRequest req,
[CosmosDB(
databaseName: "",
containerName: "",
Connection = ""
)] CosmosClient client,
ILogger log)
{
string subject = req.Query["sub"];
if (!Enum.TryParse(req.Query["idp"], out OpenIdProvider openIdProvider) || string.IsNullOrEmpty(subject))
{
var message = "";
log.LogWarning();
return _contentResultFactory.CreateContentResult(message, HttpStatusCode.BadRequest);
}
var query = client.GetContainer("", "").GetItemLinqQueryable<Clinic>()
.Where(x => x.OpenIdProvider == openIdProvider && x.Subject == subject);
Clinic clinic;
using (var iterator = query.ToFeedIterator())
clinic = (await iterator.ReadNextAsync()).FirstOrDefault();
if (clinic == null)
{
log.LogWarning();
return _contentResultFactory.CreateContentResult();
}
var response = new ClinicReadResponse(clinic);
return _contentResultFactory.CreateContentResult(response, HttpStatusCode.OK);
}
//TestFactory
public static HttpRequest HttpRequestSetup(Dictionary<string, StringValues> query)
{
var context = new DefaultHttpContext();
var request = context.Request;
request.Query = new QueryCollection(query);
request.Method = "GET";
return request;
}
In both your Clinic objects, your are generating a new GUID for the ID by calling System.Guid.NewGuid. Assuming the JSON generated from each object is the same shape (they will need to be if you want them to match), the values of each ID property will be different. Since the IDs are different, your JSON strings are not equal, therefore causing the failure.
Here is a post that will show you how to manually create a Guid. You can use this to ensure your IDs are of the same value when testing.
Assigning a GUID in C#
I don't know what your Azure Function code looks like, but your test's setup to make an HTTP request tells me you're calling the method tied to the Http Trigger. Consider the scope of what your method is doing; if it is large (or is calling other methods), this will increase the chances of your test breaking as you change the Azure Function over time. To help future-proof your test make sure the method it's calling has a single responsibility. This will make debugging your code easier to do if a change does make your test fail, and will lessen the likelihood of needing to edit your test to accommodate for code changes.

Testing Azure Function - how to create fake HTTP request that includes an item in HttpContext

We have an azure functions project and it looks like the previous dev used a similar approach as described here for unit testing:
http://dontcodetired.com/blog/post/Mocking-HttpRequest-Body-Content-When-Testing-Azure-Function-HTTP-Trigger-Functions
It works well, except that I now need to inject a fake value for the the following string:
HttpContext.Items["MS_AzureFunctionsRequestID"]
cus at some point in the code, we do this:
req.HttpContext.Items["MS_AzureFunctionsRequestID"].ToString()
And right now, the unit test is failing because the fake request object doesn't include this field.
I've tried a few different things but so far, no dice.
Assuming I'm using the following code, where can I inject this fake string:
private static Mock<HttpRequest> CreateMockRequest(object body)
{
var ms = new MemoryStream();
var sw = new StreamWriter(ms);
var json = JsonConvert.SerializeObject(body);
sw.Write(json);
sw.Flush();
ms.Position = 0;
var mockRequest = new Mock<HttpRequest>();
mockRequest.Setup(x => x.Body).Returns(ms);
return mockRequest;
}
I've tried to add an additional "sw.Write()" line and play around with the contents but I can't seem to get it working.
Thanks.
EDIT 1
So I changed the above method so it has one additional line:
private static Mock<HttpRequest> CreateMockRequest(object body)
{
var ms = new MemoryStream();
var sw = new StreamWriter(ms);
var json = JsonConvert.SerializeObject(body);
sw.Write(json);
sw.Flush();
ms.Position = 0;
var mockRequest = new Mock<HttpRequest>();
mockRequest.Setup(x => x.Body).Returns(ms);
mockRequest.Setup(x =>x.HttpContext.Items.Add("MS_AzureFunctionsRequestID", REQID));
return mockRequest;
}
REQID is a new private const that has been defined in the same class as the CreateMockRequest() method.
This is the method that ultimately calls this code:
[Fact]
public async void post_request_should_be_stored_in_queue_and_storage_table(){
var messageQueue = TestFactory.CreateAzureStorageQueue();
var request = TestFactory.CreateWidgetHTTPRequest();
Console.Write(request.HttpContext.Items["MS_AzureFunctionsRequestID"].ToString());
var storageTable = TestFactory.SaveToStorageTable();
var widgetRequest = new WidgetRequest(storageTable);
var response = (OkObjectResult)await widgetRequest.CreateWidget(request, messageQueue, logger);
Assert.NotNull(response);
Assert.True(((AzureStorageQueueTestClient<string>)messageQueue).Messages.Count > 0);
}
When it hits the console.write - the field is null.
Can I call setup on the mock object twice?
how do I set x.body and x.HttpContext?
EDIT 2
I found this post: How to mock HttpContext.Current.Items with NUnit and Rhino Mocks
I'm trying to use the answer to adapt my code, but when I try to create the httpContext object, i'm getting a CS0144 error
"Cannot create an instance of the abstract type or interface 'HttpContext'
"Cannot create an instance of the abstract type or interface 'HttpResponse'
The code I'm playing around with so far just has this:
[Fact]
public void can_create_http_context()
{
const string REQUEST_GUID_FIELD_NAME = "RequestGUID";
var httpContext = new HttpContext(new HttpRequest("", "http://google.com", ""), new HttpResponse(new StringWriter()));
HttpContext.Current = httpContext;
}

How to Unit test WEB API Controller Exception using Moq

How to Unit test IHttpActionResult Exception InternalServerError with status code 500 and message
[HttpGet]
public async Task<IHttpActionResult> Get(Guid myId)
{
try
{
var myaccount = await _myaccountService.GetMyAccount(myId);
return Ok(myaccount);
}
catch (Exception ex)
{
return InternalServerError();
}
}
Did try with Test method
[TestMethod]
public async Task GeMyAccount_WhenThrowsException_ReturnsServerError()
{
// Arrange
var exception = new Exception("Internal Server Error");
var expectedResult = new List<MyAccount>
{
new MyAccount
{
Id = "1",
Name = "Name1"
},
new MyAccount
{
Id = "2",
Name = "Name2"
},
};
var myId = new Guid();
//Act
var mockMyAccountService = new Mock<IMyAccountService>();
mockMyAccountService.Setup(mock =>
mock.GetMyAccount(myId)).Throws(exception).Verifiable();
var controller = new MyAccountController(mockMyAccountService.Object);
//Assert
var actualResult = (await controller.Get(myId) as
OkNegotiatedContentResult<MyAccount>).Content;
?? var result = actualResult as ObjectResult;
?? Assert.AreEqual(StatusCodes.Status500InternalServerError, result.StatusCode);
?? Assert.AreEqual("Internal Server Error ", result.Value);
mockMyAccountService.Verify(b => b.GetMyAccount(myId));
}
Not sure how to get the Exception and status code 500 using Moq.
As it was said by Nkosi the exception is swallowed by the try-catch block so you are not able to make any assertion against the exception.
But you can (and should) make assertion against the returned object.
[TestMethod]
public async Task GivenAFaultyMyAccountService_WhenICallGet_ThenItReturnsAnInternalServerError()
{
//Arrange
var expectedException = new Exception("Something went wrong");
var mockMyAccountService = new Mock<IMyAccountService>();
mockMyAccountService
.Setup(svc => svc.GetMyAccount(It.IsAny<Guid>()))
.Throws(expectedException);
var sut = new MyAccountController(mockMyAccountService.Object);
//Act
var actualResult = await sut.Get(Guid.NewGuid());
//Assert
Assert.IsInstanceOfType(actualResult, typeof(InternalServerErrorResult));
}
I've made the following changes to your test:
I've renamed your test to align with the Given-When-Then structure
In this test case I'm only focusing on a single situation when the underlying dependency is malfunctioning, so I've get rid of everything which is related to the happy path
The happy path should have a separate test case
I've made the mock Setup more generic by replacing the myId parameter to It.IsAny<Guid>()
I've also replaced the new Guid() to Guid.NewGuid() because the former would create an empty uuid, while the later will generate a new uuid
I've removed the Verifiable call because it is not really needed here
The Act phase is when you make the actual call against a given method, not when you are constructing the controller, so I've moved the comment to the right place
I've changed the variable name controller to sut, which stands for the System Under Test
I've replaced your hard to read assessment logic to a simple type check
InternalServerError returns an InternalServerErrorResult
MSTest's Assert class has a method called IsInstanceOf, which makes the type check more convenient
Take a look at this code
[Fact]
public async Task Test1()
{
//arrange
//prepare your data for test
//act
async Task action()
{
//run your sut action
}
//assert
var exception = await Assert.ThrowsAsync<Exception>(action);
Assert.Equal("Internal Server Error", exception.Message);
}

How can I unit test delegating handler

I have an httpClient which has timeout,retry,authorization delegating handlers.
var authorizationHandler = new AuthorizationDelegatingHandler();
var retryHandler = new RetryPolicyDelegatingHandler(3);
var timeoutHandler = new TimeOutDelegatingHandler(TimeSpan.FromSeconds(5));
authorizationHandler.InnerHandler = retryHandler;
retryHandler.InnerHandler = timeoutHandler;
_myHttpClient = new HttpClient(authorizationHandler);
I am following along a tutorial and I am trying to unit test my timeout handler
[TestMethod]
[ExpectedException(typeof(TimeoutException))]
public async Task GetDocuments_Timeout_MustThrowTimeoutException()
{
var unauthorizedResponseHttpMessageHandlerMock = new Mock<HttpMessageHandler>();
unauthorizedResponseHttpMessageHandlerMock.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()).ReturnsAsync(new HttpResponseMessage()
{
StatusCode = System.Net.HttpStatusCode.Unauthorized
});
var httpClient = new HttpClient(unauthorizedResponseHttpMessageHandlerMock.Object);
httpClient.BaseAddress = new Uri("http://localhost");
var timeoutHandler = new TimeOutDelegatingHandler(TimeSpan.FromSeconds(3));
var testableClass = new MyCustomclass(httpClient);
var cancellationSource = new CancellationTokenSource();
await testableClass.Foo();
}
I am stuck at this point. How can i chain those handlers in unit test project?
The answer is very simple you should not. What you should do is:
Unit test the units. That is a simple piece of code, design to do a single or few things.
Create tests for each handler individually.
Creat tests for the handler construction that occurs during configuration.
You should not test how the chains work as unit tests, as this broadens the scope too much and renders the unit tests unmaintainable.
That's what integration testing is for.

How do I unit test requests against SSL-only Web Api Controller?

I have a unit test which uses the OWIN TestServer class to host my Web Api ApiController classes for testing.
I first wrote the unit test when the REST API did not have the HTTPS (SSL) requirement baked into the Controller itself.
My unit test looked something like this:
[TestMethod]
[TestCategory("Unit")]
public async Task Test_MyMethod()
{
using (var server = TestServer.Create<TestStartup>())
{
//Arrange
var jsonBody = new JsonMyRequestObject();
var request = server.CreateRequest("/api/v1/MyMethod")
.And(x => x.Method = HttpMethod.Post)
.And(x => x.Content = new StringContent(JsonConvert.SerializeObject(jsonBody), Encoding.UTF8, "application/json"));
//Act
var response = await request.PostAsync();
var jsonResponse =
JsonConvert.DeserializeObject<JsonMyResponseObject>(await response.Content.ReadAsStringAsync());
//Assert
Assert.IsTrue(response.IsSuccessStatusCode);
}
}
Now that I've applied the attribute to enforce HTTPS, my unit test fails.
How do I fix my test so that, all things being equal, the test passes again?
To fix this unit test, you need to change the base address for the TestServer.
Once the server has been created set the BaseAddress property on the created object to use an "https" address. Remember the default BaseAddress value is http://localhost.
In which case, you can use https://localhost.
The changed unit test would look as follows:
[TestMethod]
[TestCategory("Unit")]
public async Task Test_MyMethod()
{
using (var server = TestServer.Create<TestStartup>())
{
//Arrange
server.BaseAddress = new Uri("https://localhost");
var jsonBody = new JsonMyRequestObject();
var request = server.CreateRequest("/api/v1/MyMethod")
.And(x => x.Method = HttpMethod.Post)
.And(x => x.Content = new StringContent(JsonConvert.SerializeObject(jsonBody), Encoding.UTF8, "application/json"));
//Act
var response = await request.PostAsync();
var jsonResponse =
JsonConvert.DeserializeObject<JsonMyResponseObject>(await response.Content.ReadAsStringAsync());
//Assert
Assert.IsTrue(response.IsSuccessStatusCode);
}
}

Categories

Resources