I have written a unit test class in C# for my MVC project.
The Test Method is following
[Test]
public void To_Add_DocumentStatusIsNull_ThrowsInvalidOperationException_ServiceTest()
{
try
{
_IDocumentStatusRepositoryMock = new Mock<IDocumentStatusRepository>();
_unitOfWorkMock = new Mock<IUnitOfWork>();
DocumentStatusService documentStatusService = new
DocumentStatusService(_unitOfWorkMock.Object,
_IDocumentStatusRepositoryMock.Object);
DocumentStatus documentStatus;
documentStatus = null;
_IDocumentStatusRepositoryMock.Setup(m => m.Add(documentStatus));
documentStatusService.Add(documentStatus);
Assert.Pass();
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
And the Service Method is following
public virtual void Add(TEntity entity)
{
try
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_repository.Add(entity);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
Now This test method only not passed due to the service class thrown ArgumentNullException.So how to handle the ArgumentNullException or How to make this test pass?
Please anybody help
If you are trying to check that the ArgumentNullException is working (which: it isn't currently). then it sounds like you want:
[Test, ExpectedException(typeof(ArgumentNullException), ExpectedMessage = #"Value cannot be null.
Parameter name: entity")]
public void To_Add_DocumentStatusIsNull_ThrowsInvalidOperationException_ServiceTest()
{
_IDocumentStatusRepositoryMock = new Mock<IDocumentStatusRepository>();
_unitOfWorkMock = new Mock<IUnitOfWork>();
DocumentStatusService documentStatusService = new
DocumentStatusService(_unitOfWorkMock.Object,
_IDocumentStatusRepositoryMock.Object);
DocumentStatus documentStatus;
documentStatus = null;
_IDocumentStatusRepositoryMock.Setup(m => m.Add(documentStatus));
documentStatusService.Add(documentStatus);
}
...
public virtual void Add(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_repository.Add(entity);
}
Testing for the ArgumentNullException
If you remove the ill-advised
catch (Exception e)
{
throw new Exception(e.Message);
}
from your code to be tested (The current catch loses context of the error, and breaks the stack trace, see below), your test can be as simple as wrapping the invocation in an Assert.Throws<ArgumentNullException>():
[Test]
public void PassingANullEntityToAddMustThrowArgumentNullException()
{
var documentStatusService = new DocumentStatusService(...);
Assert.Throws<ArgumentNullException>(() => documentStatusService.Add(null));
}
Re: Your Exception Handler
In your service code, never catch an exception and rethrow it as you've done, as this will lose the stack trace (e.g. _repository.Add(entity); could throw as well.). You also aren't adding any value by throwing e.Message as this is already in the original exception (with additional info like stack trace and inner exception)
Bad:
catch (Exception e)
{
throw new Exception(e.Message);
}
Better: If you do catch and rethrow with some value, wrap the original as an inner exception:
catch (SqlException ex)
{
throw new Exception("Some value add here", ex);
}
or if you are just intercepting and allow to propagate:
catch (SqlException)
{
// Do some logging
throw;
}
Best to me would to let the exception propagate, unless you either adding value, or handling it.
I am assuming: Looking at the code this unit test should not pass. Adding a NULL to a list is in most cases not an intended behaviour.
I see 2 options:
A) You should add a try/catch to you Test metod.
try
{
_IDocumentStatusRepositoryMock.Setup(m => m.Add(documentStatus));
documentStatusService.Add(documentStatus);
}
catch (Exception )
{
Assert.Fail(); // or nothing is expected behaviour
}
B) Remove the try/catch block from the Test Method so you do not swallow the exception. (Every Test that does not fails or an Assert or thows an unhandeled exception automatically passes)
Related
This is an example from https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library
I have tried to execute it in Visual Studio 2022, C#10, Net 6 but exception is not propagated to try catch block.
We can emulate some delay to force it to propagate (via sleep, or task.Wait(10), ...) but this is not documented.
Is this some kind of compiler optimization or is it bug?
public class Program
{
public static void Main()
{
var task = Task.Run(
() => {
//Thread.Sleep(10); //if uncomment then exception is propagated
throw new CustomException("This exception is expected!");
});
try
{
task.Wait(); //we can use task.Wait(1) then exception is caught
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
{
// Handle the custom exception.
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
// Rethrow any other exception.
else
{
throw ex;
}
}
}
}
class CustomException : Exception
{
public CustomException(string s) : base(s) { }
}
}
I need to test that exactly Argument Exception is caugtht. Is it really possible to understand that exception in method is caugtht?
public JsonResult Create(TeamViewModel teamViewModel)
{
JsonResult result = null;
try
{
// here exception throws
var domainTeam = teamViewModel.ToDomain();
...
}
catch (ArgumentException ex)
{
this.ModelState.AddModelError(string.Empty, ex.Message);
result = this.Json(this.ModelState);
}
return result;
}
My Unit test for this method:
public void Create_InvalidTeamAchievements_ArgumentExceptionThrown()
{
Exception exception = null;
string invalidAchievements = CreateInvalidTeamAchievements();
// Arrange
var viewModel = new TeamMvcViewModelBuilder().WithAchievements(invalidAchievements).Build();
var sut = _kernel.Get<TeamsController>();
// Act
try
{
sut.Create(viewModel);
}
catch (ArgumentException ex)
{
exception = ex;
}
// Assert
VerifyExceptionThrown(exception, string.Format(Resources.ValidationTeamAchievements,
Constants.Team.MAX_ACHIEVEMENTS_LENGTH));
}
You are testing it in wrong way. Functionality should be tested to not throw exception as you already have caught exception inside Create Method. Rather you should Assert that JsonResult containing your ModelState should have error in it in case exception was raised in Create method.
I am developing a MVC application.
I am trying to define my own exception classes. I am making this structure first time...
What else I have to add in my exception classes , like constructor or something , so it work well... ?
public ActionResult Edit(EmployeeVM employeeVM)
{
EmployeeService employeeService = new PartyService();
try
{
PartyService partyService = new PartyService();
partyService.Update(PartyVM);
}
catch (DuplicateEntityExcpetion e)
{
TempData["error"] = e + "Party you are trying to add is already exist.";
}
catch (InvalidDataException e)
{
TempData["error"] = e + "Data which you are trying to add is not valid.";
}
public class InvalidDataException : Exception
{
}
public class DuplicateEntityExcpetion : Exception
{
}
}
You must throw these exceptions from your service so that they get catched here.
throw new DuplicateEntityExcpetion("Your Query or Message");
throw new InvalidDataException ("Your Query or Message");
Also, it is a good practice to have a generic exception handled so that you have taken care of all exceptions.
catch (Exception e)
{
TempData["error"] = e + "Data which you are trying to add is not valid.";
}
Suppose I have this application:
class Program
{
static void Main(string[] args)
{
try
{
throw new SomeSpecificException("testing");
}
catch (SomeSpecificException ex)
{
Console.WriteLine("Caught SomeSpecificException");
throw new Exception("testing");
}
catch (Exception ex)
{
Console.WriteLine("Caught Exception");
}
Console.ReadKey();
}
}
// just for StackOverflow demo purposes
internal class SomeSpecificException : Exception
{
public SomeSpecificException(string message) : base(message)
{ }
public SomeSpecificException()
{ }
}
And my required output is as follows:
Caught SomeSpecificException
Caught Exception
Is there a way to do this? Or is my design totally off base?
Background:
I am adding code to an existing code base. The code base catches Exception (generalized exception) and does some logging, removes files, etc. But I have a unique behavior I'd like to only happen when SomeSpecificException is thrown. Afterwards, I'd like the exception handling to pass to the existing Exception catch clause so that I do not have to modify too much of the existing code.
I am aware of checking for exception's type using reflection or some other runtime technique and putting an if statement in the Exception catching clause as per Catch Multiple Exceptions at Once but I wanted to get feedback on whether the above approach is possible.
You need to use two try blocks:
try {
try {
throw ...;
} catch(SpecificException) {
// Handle
throw;
}
} catch(Exception) {
// Handle
}
Your approach will not work. The best you can do is to extract the code you want to have in common between the two handlers into a method, and have them both call the common method.
try
{
throw new SomeSpecificException("testing");
}
catch (SomeSpecificException ex)
{
Console.WriteLine("Caught SomeSpecificException");
CommonHandling();
}
catch (Exception ex)
{
CommonHandling();
}
private void CommonHandling() {
Console.WriteLine("Caught Exception");
}
Try this:
try
{
try
{
throw new InvalidCastException("testing");
}
catch (SomeSpecificException ex)
{
Console.WriteLine("Caught SomeSpecificException");
throw new Exception("testing");
}
}
catch (Exception ex)
{
Console.WriteLine("Caught Exception");
}
Console.ReadKey();
This should avoid changing the existing code much. You are just adding an additional try directly inside the existing one.
If you really want it to work this was, I suppose you could so something with a switch statement
try
{
throw new InvalidCastException("testing");
}
catch (Exception ex)
{
switch(ex.GetType())
{
case "SomeSpecificException":
Console.WriteLine("Caught SomeSpecificException");
goto default; //if I recall correctly, you need a goto to fall through a switch in c#
break;
default:
Console.WriteLine("Caught Exception");
}
Console.ReadKey();
When an exception is possible to be thrown in a finally block how to propagate both exceptions - from catch and from finally?
As a possible solution - using an AggregateException:
internal class MyClass
{
public void Do()
{
Exception exception = null;
try
{
//example of an error occured in main logic
throw new InvalidOperationException();
}
catch (Exception e)
{
exception = e;
throw;
}
finally
{
try
{
//example of an error occured in finally
throw new AccessViolationException();
}
catch (Exception e)
{
if (exception != null)
throw new AggregateException(exception, e);
throw;
}
}
}
}
These exceptions can be handled like in following snippet:
private static void Main(string[] args)
{
try
{
new MyClass().Do();
}
catch (AggregateException e)
{
foreach (var innerException in e.InnerExceptions)
Console.Out.WriteLine("---- Error: {0}", innerException);
}
catch (Exception e)
{
Console.Out.WriteLine("---- Error: {0}", e);
}
Console.ReadKey();
}
I regularly come into the same situation and have not found a better solution yet. But I think the solution suggested by the OP is eligible.
Here's a slight modification of the original example:
internal class MyClass
{
public void Do()
{
bool success = false;
Exception exception = null;
try
{
//calling a service that can throw an exception
service.Call();
success = true;
}
catch (Exception e)
{
exception = e;
throw;
}
finally
{
try
{
//reporting the result to another service that also can throw an exception
reportingService.Call(success);
}
catch (Exception e)
{
if (exception != null)
throw new AggregateException(exception, e);
throw;
}
}
}
}
IMHO it will be fatal to ignore one or the other exception here.
Another example: Imagin a test system that calibrates a device (DUT) and therefore has to control another device that sends signals to the DUT.
internal class MyClass
{
public void Do()
{
Exception exception = null;
try
{
//perform a measurement on the DUT
signalSource.SetOutput(on);
DUT.RunMeasurement();
}
catch (Exception e)
{
exception = e;
throw;
}
finally
{
try
{
//both devices have to be set to a valid state at end of the procedure, independent of if any exception occurred
signalSource.SetOutput(off);
DUT.Reset();
}
catch (Exception e)
{
if (exception != null)
throw new AggregateException(exception, e);
throw;
}
}
}
}
In this example, it is important that all devices are set to a valid state after the procedure. But both devices also can throw exceptions in the finally block that must not get lost or ignored.
Regarding the complexity in the caller, I do not see any problem there either. When using System.Threading.Tasks the WaitAll() method, for example, can also throw AgregateExceptions that have to be handled in the same way.
One more note regarding #damien's comment: The exception is only caught to wrap it into the AggregateException, in case that the finally block throws. Nothing else is done with the exception nor is it handled in any way.
For those who want to go this way you can use a little helper class I created recently:
public static class SafeExecute
{
public static void Invoke(Action tryBlock, Action finallyBlock, Action onSuccess = null, Action<Exception> onError = null)
{
Exception tryBlockException = null;
try
{
tryBlock?.Invoke();
}
catch (Exception ex)
{
tryBlockException = ex;
throw;
}
finally
{
try
{
finallyBlock?.Invoke();
onSuccess?.Invoke();
}
catch (Exception finallyBlockException)
{
onError?.Invoke(finallyBlockException);
// don't override the original exception! Thus throwing a new AggregateException containing both exceptions.
if (tryBlockException != null)
throw new AggregateException(tryBlockException, finallyBlockException);
// otherwise re-throw the exception from the finally block.
throw;
}
}
}
}
and use it like this:
public void ExecuteMeasurement(CancellationToken cancelToken)
{
SafeExecute.Invoke(
() => DUT.ExecuteMeasurement(cancelToken),
() =>
{
Logger.Write(TraceEventType.Verbose, "Save measurement results to database...");
_Db.SaveChanges();
},
() => TraceLog.Write(TraceEventType.Verbose, "Done"));
}
As the comments have suggested this may indicate "unfortunately" structured code. For example if you find yourself in this situation often it might indicate that you are trying to do too much within your method. You only want to throw and exception if there is nothing else you can do (your code is 'stuck' with a problem you can't program around. You only want to catch an exception if there is a reasonable expectation you can do something useful. There is an OutOfMemoryException in the framework but you will seldom see people trying to catch it, because for the most part it means you're boned :-)
If the exception in the finally block is a direct result of the exception in the try block, returning that exception just complicates or obscures the real problem, making it harder to resolve. In the rare case where there is a validate reason for returning such as exception then using the AggregateException would be the way to do it. But before taking that approach ask yourself if it's possible to separate the exceptions into separate methods where a single exception can be returned and handled (separately).