Assert Method not reached in Try-Catch statement - c#

I am trying to unit test my code to see if I try to view an account's details without a sessionKey, it will throw an exception. The unit test will go and execute the statement in the try-catch and despite knowing an exception will occur, it lists the test as successful even though Assert should be false. Assert is reached in similar functions, but not always. What would be the cause of the problem?
Original Function
/// <summary>
/// Displays the account details to the user
/// </summary>
/// <returns>HttpResponseMessage deserialized into AccountResponses object</returns>
public async Task<AccountResponse> Details()
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Session-Key", sessionKey);
try
{
HttpResponseMessage response = await client.GetAsync(_baseUrl + "/Account/Details");
response.EnsureSuccessStatusCode();
string details = await response.Content.ReadAsStringAsync();
AccountResponse temp = JsonConvert.DeserializeObject<AccountResponse>(details);
return temp
}
catch (HttpRequestException ex)
{
throw ex;
}
}
Working Live Unit Test Function
[TestCategory("Account/Logon")]
[TestMethod]
public void LogOnNegativeBadPasswordTest()
{
try
{
string sessionKey = dmWeb.Account.LogOn(new DMWeb_REST.AccountLogOn { Password = "test#pasasdfasfsword" }).GetAwaiter().GetResult().ToString();
}
catch (HttpRequestException ex)
{
Assert.IsTrue(ex.Message.Contains("400"));
}
}
Not Working Live Unit Test Function
[TestCategory("Account/Details")]
[TestMethod]
public void DisplayDetailsNegativeNoSessionKeyTest()
{
try
{
string details = dmWeb.Account.Details().GetAwaiter().GetResult().ToString();
}
catch (HttpRequestException ex)
{
Assert.IsTrue(ex.Message.Contains("401"));
}
}

The test will be treated as successful as long as no errors are thrown. If no error is being caught in the catch block, this almost definitely means that no error was thrown by the code you're testing.
So place an Assert.Fail() after the statement that's supposed to throw an error:
public void TestMethod()
{
try
{
string details = ThingIAmTesting();
// shouldn't get here
Assert.Fail();
}
catch (Exception ex)
{
Assert.IsTrue(ex.Message.Contains("401");
}
}

Related

How to handle exception in AWS Lambda in C# for reprocessing

I am a beginner in AWS and at present, I am sending data from DyanmoDB leveraging on TTL to AWS Lambda and then to an End Point. My manager wants me to handle a situation where Lambda throws some exception thus fails to deliver the events to an endpoint.
In case of exception from Lambda he wants me to send the entry back to the DynamoDB table. I am sure it should be doable by using Put-Item command. But I want to know is there any out of the box solution that Lambda provides with which I can handle the failure condition and reprocess that received event data, and thus not lose the entries from DyanmoDB Stream during an exception. By doing this I won't have to send the data back to DynamoDB.
Below is working code for AWS Lambda
public class Function
{
private JsonSerializer _jsonSerializer = new JsonSerializer();
private readonly IQueueClient client;
public async Task FunctionHandler(DynamoDBEvent dynamoEvent, ILambdaContext context)
{
try
{
foreach (var record in dynamoEvent.Records)
{
try
{
if (record.EventName == OperationType.REMOVE)
{
context.Logger.LogLine("Calling SerializeStreamRecord function");
string streamRecordJson = SerializeStreamRecord(record.Dynamodb);
Debug.Write(streamRecordJson);
await SendAsync(streamRecordJson, context);
context.Logger.LogLine("Data Sent");
}
}
catch (Exception ex)
{
throw ex;
}
}
}
catch (Exception ex)
{
context.Logger.LogLine("Exception Occurred" + ex.Message);
}
context.Logger.LogLine("Stream processing complete.");
}
private async Task SendAsync(string stream, ILambdaContext context)
{
try
{
var message = new Message(Encoding.UTF8.GetBytes(stream));
await client.SendAsync(message); // SEND MESSAGE
}
catch (Exception ex)
{
throw ex;
}
}
private string SerializeStreamRecord(StreamRecord streamRecord)
{
try
{
using (var writer = new StringWriter())
{
_jsonSerializer.Serialize(writer, streamRecord);
return writer.ToString();
}
}
catch (Exception ex)
{
throw ex;
}
}
}

Error handling in the repository (API REST)

I have this situation (method in Repository):
public string Get(string name)
{
string response;
try
{
using (var context = new MyDB())
{
var row = context.TblSomething.FirstOrDefault();
response = row.GetType().GetProperty(name).GetValue(row, null).ToString();
}
return response;
}
catch (SqlException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
}
When there is content other than the Property in the name field, it throws an exception
The method is called in the Controller
public IActionResult Get(string name)
{
string response;
try
{
response = _module.MyRepository().Get(name);
}
catch (ValidationException e)
{
return BadRequest(new { error = new { message = e.Message, value = e.Value } });
}
return Ok(response);
}
How to make it not return a 500 error to the user but should be BadRequest?
The way to make it return 400 instead of 500 is to actually catch the exception. You already have a catch block that returns BadRequest, so the only assumption that can be made is that ValidationException is not what's being thrown. Catch the actual exception being thrown and you're good.
That said, absolute do not catch an exception merely to throw the same exception. All you're doing is slowing down your app. You should also never catch Exception, unless you're simply trying to generally log all exceptions and then rethrow. If you don't have a specific handler for an exception type, then don't catch it. In other words, remove these lines:
catch (SqlException e)
{
throw e;
}
catch (Exception e)
{
throw e;
}
If you're not going to handle any exceptions as your repo code does, then don't use a try block at all.
It's also worth mentioning that you shouldn't rely on exceptions unless you have to. Throwing exceptions is a drain on performance. In a situation like this, you should simply return null, instead of throwing an exception when there's no matching property. Then, you can do a null check to verify instead of a try/catch.
You could create your own Exception Handling Middleware to catch 500 error and return your custom error status code and message.
1.Create the middleware:
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
public ExceptionHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context )
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
string message = "Something is wrong!";
httpStatusCode = HttpStatusCode.BadRequest; // Or whatever status code you want to return
message = exception.Message; // Or whatever message you want to return
string result = JsonConvert.SerializeObject(new
{
error = message,
});
context.Response.StatusCode = (int)httpStatusCode;
context.Response.ContentType = "application/json";
return context.Response.WriteAsync(result);
}
}
2.Add it into the middleware pipeline after app.UseDeveloperExceptionPage();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMiddleware(typeof(ExceptionHandlingMiddleware));
}

Application specific exception wrapping "MongoDuplicateKeyException" not catch'ed

Out of need have created application exception which wraps a MongoDuplicateKeyException and throwing that exception like below
Public class AppException : Exception
{
// all constructor implementation
public int ErrorCode { get; set; }
public string AppMessage { get; set; }
}
In method catching and throwing exception
public async Task<Response> Method1(parameter ...)
{
try
{
//some insert/update operation to DB
return <instance of Response>;
}
catch(MongoduplicateKeyException ex)
{
var exception = new AppException(ex.Message, ex)
{
ErrorCode = 22,
AppMessage = "some message",
};
throw exception;
}
}
Method that calls Method1() above
try
{
//some other operation
var response = await Method1();
}
catch(AppException ex)
{
SomeOtherLoggingMethod(ex, other parameter);
}
catch(Exception ex)
{
SomeMethod(ex, other parameter);
}
Surprisingly the catch(AppException ex) catch block never gets catched even though am throwing an AppException from Method1(). It always catch the generic catch block catch(Exception ex).
After debugging, found that in catch(Exception ex) catch block the exception type ex.GetType() is actually a WriteConcernException type (MongoduplicateKeyException : WriteConcernException).
So essentially that specific catch block not hitting cause the exception type is not AppException rather WriteConcernException But
Not sure why is it so? am I missing something obvious here? Please suggest.
You found the answer while debugging. The catch(AppException ex) block is not executed because public async Task<Response> Method1 does not throw an AppException it throws a WriteConcernException.
The API shows a WriteConcernException is the superclass of DuplicateKeyException so the catch block in Method1 is not hit and the exception bubbles up to the 2nd catch block in the caller.
So if you update your code to catch the appropriate exception it should work as you intend.
public async Task<Response> Method1(parameter ...)
{
try
{
//some insert/update operation to DB
return <instance of Response>;
}
catch (MongoServerException mse)
...

How to log the "path taken" by the code and its exceptions

I have a requirement of compose the log message through the path taken by a code in a user click. Let me give an example:
Imagine the classical example: A user clicks in a button in a View, that calls code from the Business Layer that call code from Data Access Layer, that returns data to the Business, that return to a View.
I want to compose my log message through these layers. The caller method (in a View) that started the whole process will receive the full message. Here are some code sample just to help me explain what i am trying to achieve.
public void ViewMethod()
{
try
{
BussinessMethod();
}
catch (Exception ex)
{
Logger.Enqueue("exception occured");
Logger.Print();
}
}
public void BussinessMethod()
{
try
{
DataAcessMethod();
}
catch (Exception ex)
{
Logger.Enqueue("exception occured in the bussiness method")
}
}
public void DataAcessMethod()
{
try
{
// some code that executes an SQL command
// Log the SQL Command 1
// Log the SQL Command 2 and do on...
}
catch (Exception ex)
{
Logger.Enqueue("Error occurred, sqls executed are ...", sqlExecuted);
}
}
EDIT: The reason i am needing it is that i need to log all the SQL's executed in the whole process. If an error occurs in any point of the whole process, the user cant be warned, i need to store as much as possible information becouse the support technician will need it later.
My question is if there is any design pattern to develop it or passing a Logger reference across the "layers" are acceptable?
I would do something like this
public class Context
{
[ThreadStatic]
private static LogStore _store;
public static Log(....)
{
.....
}
}
public void ViewMethod()
{
var response = BussinessMethod();
if (response.Status = ResponseStatus.Success)
// do something with response.Data
else
// show message?
}
public BusinessMethodResponse BussinessMethod()
{
var response = new BusinessMethodResponse() {Status = ResponseStatus.Failure};
SomeData data;
try
{
data = DataAcessMethod();
}
catch (Exception ex)
{
Context.Log(....);
response.Message = "Data retrieval failed";
return response;
}
try
{
// massage the data here
response.Status = ResponseStatus.Success;
response.Data = myMassagedData;
}
catch (Exception ex)
{
Context.Log(....);
response.Message = "Something failed";
}
return response;
}
public void DataAcessMethod()
{
// some code that executes an SQL command
}
What this do? Now you can call your business objects from MVC, WPF, WinForms, Web Forms, etc...

Unit test for web api action method responds while exception

I was trying to write some unit tests for an web api action method while exception. So below my action method
[Route("{userName}/{searchCriteria}")]
[HttpGet]
public IHttpActionResult Events(string accountNumber, string searchCriteria)
{
try
{
bool isInputValid = _inputValidation.IsTrackingEventInputValid(accountNumber, searchCriteria);
if (isInputValid)
{
return OK ("my data");
}
else
{
throw new ArgumentException();
}
}
catch (ArgumentException ae)
{
return new ResponseMessageResult(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ExceptionHandlingMessages.InvalidArgumentException));
}
catch (Exception ex)
{
return new ResponseMessageResult(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ExceptionHandlingMessages.InternalServerError));
}
}
I want to check responds status code and responds messages while exception occurs. But problem is as soon as my execution hits ResponseMessageResult code it throws another ArgumentNullException saying Value cannot be null.Parameter name: request. Because of that control never returns to my unit test method.
My unit test method as
[TestMethod]
public void Events()
{
_mockInputValidation.Setup(x => x.IsTrackingEventInputValid(It.IsAny<string>(), It.IsAny<string>())).Returns(false);
//act
IHttpActionResult actionResult = _trackingEventController.Events(string.Empty, string.Empty);
//assert
}
I also tries putting [ExpectedException(type)] but not much helpful
how can I solve this
Refactor your code to try and avoid throwing exceptions in your actions. Let the exception handler/filter handle them (cross-cutting concerns). Your original issue could have happened if you did not provide a proper request message for unit test.
[Route("{userName}/{searchCriteria}")]
[HttpGet]
public IHttpActionResult Events(string accountNumber, string searchCriteria) {
bool isInputValid = _inputValidation.IsTrackingEventInputValid(accountNumber, searchCriteria);
if (isInputValid) {
return Ok("my data");
} else {
return BadRequest(ExceptionHandlingMessages.InvalidArgumentException);
}
}
And then for the particular test case
[TestMethod]
public void IsTrackingEventInputValid_When_False_Should_Return_BadRequest() {
//Arrange
_mockInputValidation.Setup(x => x.IsTrackingEventInputValid(It.IsAny<string>(), It.IsAny<string>())).Returns(false);
var expected = ExceptionHandlingMessages.InvalidArgumentException;
//Act
var actionResult = _trackingEventController.Events(string.Empty, string.Empty) as BadRequestErrorMessageResult;
//Assert
Assert.IsNotNull(actionResult);
Assert.AreEqual(expected, actionResult.Message);
}

Categories

Resources