Why can't I detect this Exception in my Tests - c#

I am writing an Intigration test using nUnit in C#.
My code is:
public async Task<bool> WriteData(Document data, string tableName)
{
try
{
var table = Table.LoadTable(_dynamoDbClient, tableName);
table.PutItem(data);
return true;
}
catch (Exception e)
{
_logger.Info("Failed Writing Record");
_logger.Info("Error: " + e.Message);
return false;
}
}
My Test is:
public void TestToSeeIfWeGetAnExceptionWhenProvidingBadDataToTheDatabase()
{
// arrange
var item = new Document
{
["Id"] = "1001",
["TransactionID"] = 111111,
["StatementType"] = "TestBank"
};
_bankStatementTable = "does-not-exist";
// act / assert
Assert.Catch<System.Exception>(() => _awsDynamoDbManager.WriteData(item, _bankStatementTable));
}
Because I am passing bad data to the database I expect an exception and I get one.
However, the test fails.
I get this message from the test runner:
Expected: instance of <System.Exception>
But was: null
If I run the test in Debug I can see the Catch being hit.
What am I missing?

You should update your code a little bit. Rethrow an Exception in catch block and use ThrowsAsync
catch (Exception e)
{
_logger.Info("Failed Writing Record");
_logger.Info("Error: " + e.Message);
throw;
}
...
Assert.ThrowsAsync<System.Exception>(async () => await _awsDynamoDbManager.WriteData(item, _bankStatementTable));
Or check that WriteData returns false by making test as async as well and call Assert.IsFalse
public async Task TestToSeeIfWeGetAnExceptionWhenProvidingBadDataToTheDatabase()
{
// arrange
...
// act / assert
var result = await _awsDynamoDbManager.WriteData(item, _bankStatementTable);
Assert.IsFalse(result);
}
Since there is no awaitable code inside WriteData method, you can make it synchronous one and use Task.FromResult as return result or make it even simpler and remove using of Task<bool>
public bool WriteData(Document data, string tableName)
{
try
{
var table = Table.LoadTable(_dynamoDbClient, tableName);
table.PutItem(data);
return true;
}
catch (Exception e)
{
_logger.Info("Failed Writing Record");
_logger.Info("Error: " + e.Message);
return false; //or throw;
}
}
And the synchronous test code
Assert.Throws<System.Exception>(() => _awsDynamoDbManager.WriteData(item, _bankStatementTable));
or
public void TestToSeeIfWeGetAnExceptionWhenProvidingBadDataToTheDatabase()
{
// arrange
...
// act / assert
var result = _awsDynamoDbManager.WriteData(item, _bankStatementTable);
Assert.IsFalse(result);
}

Because you are returning false in case of Exception:
catch (Exception e)
{
_logger.Info("Failed Writing Record");
_logger.Info("Error: " + e.Message);
return false;
}
Use throw clause.

Related

Continue try block after catch. Log all exceptions in one try catch

I want to do 4 actions and each one can throw an exception. I need to execute them all and log all errors that happened along the way
I can do it in a big and clumsy way :
var exceptions = new List<ExceptionType1>();
try {
result1 = await action1();
} catch (ExceptionType1 ex1) {
exceptions.Add(ex1);
logger.Log(ex1);
}
try {
result2 = await action2();
} catch (ExceptionType1 ex1) {
exceptions.Add(ex1);
logger.Log(ex1);
}
try {
result3 = await action3(result1);
} catch (ExceptionType2 ex2) {
var ex1 = new ExceptionType1(ex2);
exceptions.Add(ex1);
logger.Log(ex1);
}
try {
result4 = await action4(result2);
} catch (ExceptionType2 ex2) {
var ex1 = new ExceptionType1(ex2);
exceptions.Add(ex1);
logger.Log(ex1);
}
if (exceptions.Count > 0) {
return false;
}
Obviously sometimes things like that bloat in size quickly
I would like to do it in more elegant way :
var exceptions = new List<ExceptionType1>();
try {
result1 = await action1();
result2 = await action2();
result3 = await action3(result1);
result4 = await action4(result2);
} catch(Exception ex) {
var ex1 = new ExceptionType1(ex);
exceptions.Add(ex1);
logger.Log(ex1);
???
~~Goto try block and continue executing~~
???
}
if (exceptions.Count > 0) {
return false;
}
I tried to find info how to get back into try block and continue executing but was unsuccessfull. Is it possible. Is there any other way around the problem that I didn't consider?
One way I guess (given your reequipments) is to create a local method
var exceptions = new List<Exception>();
async Task<T> DoAsync<T>(Func<Task<T>> func)
{
try
{
return await func();
}
catch (Exception ex)
{
exceptions.Add(ex);
logger.Log(ex);
}
return default;
}
result1 = await DoAsync(action1);
result2 = await DoAsync(action2);
if (exceptions.Count > 0)
{
return false;
}
Maybe you can extract this into a local function:
// declare this inside the method that contains the code you showed
async void GetResult<TResult, TException>(out TResult result, Func<Task<TResul>> resultGetter, Func<TException, ExceptionType1> mapper)
where TException: Exception {
try {
result = await resultGetter();
} catch (TException ex) {
var ex1 = mapper(ex)
exceptions.Add(ex1);
logger.Log(ex1);
}
}
Callers:
GetResult(out result1, action1, (ExceptionType1 e) => e);
GetResult(out result2, action2, (ExceptionType1 e) => e);
GetResult(out result3, async () => await action3(result1), (ExceptionType2 e) => new ExceptionType1(e));
GetResult(out result4, async () => await action4(result2), (ExceptionType2 e) => new ExceptionType1(e));
how to get back into try block and continue executing.. Is it possible?
You can't do what you are looking for: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch
The block is executed until an exception is thrown or it is completed successfully.
Once out of the block, even the variables that have been initialized are rolled back.
It's the whole point of the exception to stop the execution of the safe guarded code.
Follow the recommendations of the other two answers to simplify your code
I think WhenAll() method for Task will suit your purpose:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch#taskwhenall-example
First of all, your actions are already async. Moreover, you can divide to several WhenAll() blocks if you need to follow any order of execution
Example from docs:
public async Task action1()
{
throw new InvalidOperationException();
}
public async Task action2()
{
throw new NotImplementedException();
}
public async Task action3()
{
throw new InvalidCastException();
}
public async Task DoMultipleAsync()
{
Task theTask1 = action1();
Task theTask2 = action2();
Task theTask3 = action3();
Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3);
try
{
await allTasks;
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
Console.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
foreach (var inEx in allTasks.Exception.InnerExceptions)
{
Console.WriteLine("Task Inner Exception: " + inEx.Message);
}
}
}
// Output:
// Exception: Operation is not valid due to the current state of the object.
// Task IsFaulted: True
// Task Inner Exception: Operation is not valid due to the current state of the object.
// Task Inner Exception: The method or operation is not implemented.
// Task Inner Exception: Specified cast is not valid.

Task<T>.Factory.StartNew in ASP.NET MVC

I'm stuck with a problem. I need help...
In general, I have an ASP.NET MVC 5 project. When a user clicks on "Save" button, I run some code in a new created task. I need to know the result of operation, so I return the instance of my class ChangesMade. Then I serialze the object to JSON format and pass to a view. Then I check if result is true, I open an url in a new window.
So, in my controller I have the following:
public async Task<ActionResult> Save(here some parameters)
{
var changes = await _model.SaveAsync(some parameters);
return NewtownJson(changes);
}
The main saving logic is the following:
public async Task<ChangesMade> SaveAsync(some parameters here)
{
var data = (await _model.GetData(some parameter)).ToList();
// create a task of ChangesMade that contains public bool property MemoAdded
// that I need to pass to a view to know the result of operation
var task = Task<ChangesMade>.Factory.StartNew(() =>
{
ChangesMade changes = new ChangesMade();
try
{
using (var tr = new TransactionScope())
{
// some code here omitted for simplicity…
// if (someCondition == true) changes.MemoAdded = true;
tr.Complete();
}
return changes;
}
catch (Exception ex)
{
throw ex;
}
});
try
{
task.Wait();
}
catch (AggregateException ex)
{
string msg = "";
msg= ex.Flatten().InnerExceptions
.Where(e => e != null)
.Select(e => e.Message)
.Aggregate(msg, (current, message) => current + " " + message + ";")
.TrimEnd(';');
throw new Exception(msg);
}
return task.Result;
}
I publish the project on two sites on IIS. The first works fine. But the second doesn't - by some reason, it always returns changes.MemoAdded false to the view.
I can't find out a reason of that. I don't have a clue what to do ...

C# Cannot await in the body of a catch clause [duplicate]

I have the following code:
WebClient wc = new WebClient();
string result;
try
{
result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
}
catch
{
result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );
}
Basically I want to download from a URL and when it fails with an exception I want to download from another URL. Both time async of course. However the code does not compile, because of
error CS1985: Cannot await in the body of a catch clause
OK, it's forbidden for whatever reason but what's the correct code pattern here?
EDIT:
The good news is that C# 6.0 will likely allow await calls both in catch and finally blocks.
Update: C# 6.0 supports await in catch
Old Answer: You can rewrite that code to move the await from the catch block using a flag:
WebClient wc = new WebClient();
string result = null;
bool downloadSucceeded;
try
{
result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
downloadSucceeded = true;
}
catch
{
downloadSucceeded = false;
}
if (!downloadSucceeded)
result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );
Awaiting in a catch block is now possible as of the End User Preview of Roslyn as shown here (Listed under Await in catch/finally) and will be included in C# 6.
The example listed is
try … catch { await … } finally { await … }
Update: Added newer link, and that it will be in C# 6
This seems to work.
WebClient wc = new WebClient();
string result;
Task<string> downloadTask = wc.DownloadStringTaskAsync(new Uri("http://badurl"));
downloadTask = downloadTask.ContinueWith(
t => {
return wc.DownloadStringTaskAsync(new Uri("http://google.com/")).Result;
}, TaskContinuationOptions.OnlyOnFaulted);
result = await downloadTask;
Give this a try:
try
{
await AsyncFunction(...);
}
catch(Exception ex)
{
Utilities.LogExceptionToFile(ex).Wait();
//instead of "await Utilities.LogExceptionToFile(ex);"
}
(See the Wait() ending)
Use C# 6.0. see this Link
public async Task SubmitDataToServer()
{
try
{
// Submit Data
}
catch
{
await LogExceptionAsync();
}
finally
{
await CloseConnectionAsync();
}
}
You could put the await after the catch block followed by a label, and put a goto in the try block.
(No, really! Goto's aren't that bad!)
The pattern I use to rethrow the exception after await on a fallback task:
ExceptionDispatchInfo capturedException = null;
try
{
await SomeWork();
}
catch (Exception e)
{
capturedException = ExceptionDispatchInfo.Capture(e);
}
if (capturedException != null)
{
await FallbackWork();
capturedException.Throw();
}
You can use a lambda expression as follows:
try
{
//.....
}
catch (Exception ex)
{
Action<Exception> lambda;
lambda = async (x) =>
{
// await (...);
};
lambda(ex);
}
In a similar instance, I was unable to await in a catch block. However, I was able to set a flag, and use the flag in an if statement (Code below)
---------------------------------------...
boolean exceptionFlag = false;
try
{
do your thing
}
catch
{
exceptionFlag = true;
}
if(exceptionFlag == true){
do what you wanted to do in the catch block
}

Overriding SaveChangesAsync when enclosed inside TransactionScope?

I'm fairly new to EF transactions, this is the code that is used for saving
public bool Save(TbArea area, bool isNew, out string errMsg)
{
try
{
errMsg = string.Empty;
using (var oScope = new System.Transactions.TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(120)))
{
try
{
TbArea oEntity = oContext.TbArea.Where(a => a.AreaCode == area.AreaCode && a.CompanyId == MainClass.SystemCompanyId).FirstOrDefault();
if (oEntity != null)
{
if (isNew) { errMsg = Resources.ResSales.MsgRecordCodeDublicated; return false; }
oContext.TbArea.Attach(oEntity);
oContext.Entry(oEntity).CurrentValues.SetValues(area);
}
else
{
if (!isNew) { errMsg = Resources.ResSales.MsgRecordNotFoundInDB; return false; }
oContext.TbArea.Add(area);
}
oContext.SaveChangesAsync();
oScope.Complete();
return true;
}
catch (Exception ex)
{
oScope.Dispose();
errMsg = ex.Message;
return false;
}
}
I'm overriding SaveChangesAsync
so that I can save the ChangeTracker.Entries into the database.
this is a portion of the code:
dbContext.AcceptAllChanges();
logsSet.AddRange(audits);
int result = 0;
try
{
result = await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
//scope.Complete(); there was a transaction that I commented out, I thought it might overlaps the original transaction!
return result;
}
catch (Exception ex)
{
var m = ex.Message;
return result;
}
When I save an item, I get the error :
the transaction has aborted
when I remove the transaction scope the saving happens normally!
Your code is marking the transaction complete before the changes have finished saving:
oContext.SaveChangesAsync();
oScope.Complete();
You need to use await:
await oContext.SaveChangesAsync();
oScope.Complete();
If you're in a context where await can resume on a different thread, you'll probably also need to specify TransactionScopeAsyncFlowOption.Enabled.

Returning result in nested try catch block

I am implementing some performance counters and I would like to know your opinion.
The question is should I declare response and return it outside try block or Is it OK to return it directly in the try block. Is there a difference and If so, what sample code is valid (if any).
With best regards, no9.
public string TestMethod(string document)
{
try
{
WebService ws = new WebService();
string response = null;
var startTime = PerformanceCounter.GetPerformanceCounterStartTimeHandle();
try
{
response = ws.InsertDocument(document);
}
catch (Exception ex)
{
PerformanceCounterHelper.Increment(PerformanceCounterEnum.NumberOfExternalWsCallsExceptionOnSec);
throw;
}
finally
{
PerformanceCounterHelper.IncrementPerformanceCounterByElapsedTime(PerformanceCounterEnum.DurationOfExternalCallsInSec, startTime);
PerformanceCounterHelper.Increment(PerformanceCounterEnum.NumberOfExternalCallsOnSec);
}
return response;
}
catch (Exception ex)
{
log.EventError(ex);
throw new DocumentGeneralException();
}
}
versus:
public string TestMethod(string document)
{
try
{
WebService ws = new WebService();
var startTime = PerformanceCounter.GetPerformanceCounterStartTimeHandle();
try
{
return ws.InsertDocument(document);
}
catch (Exception ex)
{
PerformanceCounterHelper.Increment(PerformanceCounterEnum.NumberOfExternalWsCallsExceptionOnSec);
throw;
}
finally
{
PerformanceCounterHelper.IncrementPerformanceCounterByElapsedTime(PerformanceCounterEnum.DurationOfExternalCallsInSec, startTime);
PerformanceCounterHelper.Increment(PerformanceCounterEnum.NumberOfExternalCallsOnSec);
}
}
catch (Exception ex)
{
log.EventError(ex);
throw new DocumentGeneralException();
}
}
As long as there isn't a difference because of not exiting (i.e. it runs additional/different code), then the code is identical. Actually, at the IL level it is illegal to ret from inside a try/catch, so one of the things the compiler does is to do exactly what you have done: introduce a local, assign the local inside the try/catch, then return that value when outside the try/catch.
Basically, go with whatever is simplest and most convenient to read. In your case, I would say "the first one".

Categories

Resources