Exception not thrown by mocked object - c#

Objective is to unit test a PUBLIC VOID Method.
I have a mocked service, which my class-under-test would call, in a for-each loop with 3 different parameters.
The class-under-test passes some input parameters to "SendRequest" method of the service which executes using those parameters.
I want the mocked service to throw an exception when one of the parameters has a specific value e.g "abc".
I use something like this:
public class ClassUnderTest
{
private IMyService _myservice;
public ClassUnderTest(IMyService myservice)
{
_myservice = myservice;
}
public void MyMethod()
{
//assume I get those 3 values from somewhere, in here.
var list = new List<string>{"abc","aaa","bbb"};
foreach(var item in list)
{
try
{
_myservice.SendRequest(item);
}
catch(Exception ex)
{
//do some logging and continue calling service with next item in list
}
}
}
}
var myService = new Mock<IMyService>();
myService.Setup(x => x.SendRequest("abc")).Throws<Exception>();
myService.Setup(x => x.SendRequest("aaa"));
myService.Setup(x => x.SendRequest("bbb"));
var classUnderTest = new ClassUnderTest(myService.Object);
classUnderTest.MyMethod();
myService.Verify(x =>x.SendRequest(It.IsAny<string>()), Times.Exactly(2));
More Context:
As MyMethod returns void, to test it, I can only rely on the the fact that my dependencies were invoked at different portions of the code in this method. For e.g. if there is a null check for input parameters before service call, the method would return before it invokes the service. If it goes past null check, the dependency service would be invoked. I would be able to trace these in the code coverage results( and in debug mode).
When I run the test, it fails because its invoking the service thrice but I expect the invocation to happen twice(now may be I am wrong and may be that although it is supposed to throw exception the invocation attempt is still counted by Verify call and hence I get 3 runs).
Whatever be the case, on debug I see that the service never throws exception. I have a try-catch in the for-each-loop where I want to do some logging and continue calling the service again with the next value. But I never get to get inside the Catch block.
What am I doing wrong?

Option 1: Specific Exception
My 1st suggestion would throw a more specific exception so you can be more sure.
Option 2: Inject an ILogger service
Refactor out the logging into an ILogger and inject that in. Then pass a mock of that in and assert against it.
Option 3: Extract and Override
If you must check catch block was hit you can use extract and override:
public class ClassUnderTest
{
private IMyService _myservice;
public ClassUnderTest(IMyService myservice)
{
_myservice = myservice;
}
public void MyMethod()
{
//assume I get those 3 values from somewhere, in here.
var list = new List<string>{"abc","aaa","bbb"};
foreach(var item in list)
{
try
{
_myservice.SendRequest(item);
}
catch(Exception ex)
{
LogError(ex);
}
}
}
protected virtual LogException(Exception ex)
{
//do logging
}
}
public class TestableClassUnderTest : ClassUnderTest
{
public bool LoggingWasCalled { get; set; }
protected virtual LogException(Exception ex)
{
LoggingWasCalled = true;
}
}
Then you could sheck something like this:
var testableSut = new TestableClassUnderTest ();
testableSut.MyMethod("abc");
Assert.True(testableSut.LoggingWasCalled);
I walk through it in more detail here: http://devonburriss.me/testing-the-untestable/

Related

Database function Mock is not working in c# web api unit testing

Here is my controller method
[HttpPost]
[Authorize]
[Route(RouteConfig.Routes.LovList.contactStatus)]
public IHttpActionResult ContactStatusList()
{
try
{
var result = new DBClass.HeroDb().GetList(
DBClass.DBConstants.ListConstants.query_Contact_Status);
return Json(new Models.Response(
Models.ResponseMessages.Success,
result)
);
}
catch(System.Data.SqlClient.SqlException)
{
return InternalServerError();
}
catch(System.Exception ex)
{
Logger.Error(ex, ex.Message, ex.StackTrace);
return InternalServerError();
}
}
and this is my test case method
[TestMethod()]
public void ContactStatusListTest()
{
Mock<DBClass.HeroDb> mock = new Mock<DBClass.HeroDb>();
mock.Setup(x => x.GetList(DBClass.DBConstants.ListConstants.query_Contact_Status))
.Returns(CreateContactList());
var result = new ListController().ContactStatusList();
Models.Response response = (Models.Response)result;
Assert.AreEqual(response.Message, Models.ResponseMessages.Success);
Assert.IsNotNull(response.Data);
}
public System.Data.DataTable CreateContactList()
{
DataTable table = new DataTable();
table.Columns.Add("ContactStatus");
DataRow row1 = table.NewRow();row1["ContactStatus"] = "Contacted"; table.Rows.Add(row1);
DataRow row2 = table.NewRow(); row2["ContactStatus"] = "Not Contacted"; table.Rows.Add(row2);
DataRow row3 = table.NewRow(); row3["ContactStatus"] = "Contacted"; table.Rows.Add(row3);
return table;
}
I tried to mock GetList() function in my test method but it is not working. Controller method is giving an Internal server error . Because conrol is going to
var result = new DBClass.HeroDb()
.GetList(DBClass.DBConstants.ListConstants.query_Contact_Status);
this line and db object is null here. Please help as i am beginner in unit test case building .
First of all let's set the basis first: unit testing is different than integration testing.
In that case this is a unit test on the controller's method ContactStatusList. You're testing only this method and you actually did things correctly by trying to mock your HeroDb object. Note that you decided to mock this object because this is a dependency.
The problem is you set up the Mock but you don't use it because in your ContactStatusList method you call new DBClass.HeroDb().
There's a 2nd problem is that you're trying to mock a class. This is actually possible but all the class's methods you want to mock must be declared as virtual. Therefore it's actually better to mock an interface instead.
This interface should be received in the constructor of your ListController. On a regular execution of your Web Project inject an instance of that interface in the startup but in unit tests feed your mock to the ListController's constructor.
Remember this rule: Any dependency should be received by your controller's constructor
Here is your interface and your DbHero class
public interface IDbHero
{
IEnumerable<Contact> GetList(QueryContactStatus status);
}
public class DbHero : IDbHero
{
public IEnumerable<Contact> GetList(QueryContactStatus status)
{
// Implementation here
}
}
Now here's your controller:
[ApiController]
[Route("api/[controller]")]
public class ListController: ControllerBase
{
private readonly IHeroDb _heroDb;
public ListController(IHeroDb heroDb)
{
_heroDb = heroDb ?? throw new ArgumentNullException(nameof(heroDb));
}
[HttpPost]
[Authorize]
[Route(RouteConfig.Routes.LovList.contactStatus)]
public IHttpActionResult ContactStatusList()
{
try
{
var result = _heroDb.GetList(DBClass.DBConstants.ListConstants.query_Contact_Status);
return Json(new Models.Response(
Models.ResponseMessages.Success,
result)
);
}
catch(System.Exception ex)
{
Logger.Error(ex, ex.Message, ex.StackTrace);
throw;
}
}
}
Note that I removed the block where you only catch the SqlException because anyway if you've an unhandled exception the server will return an internal server error so it's useless to catch it if you don't even log the error.
Also in the 2nd catch block I just throw so the server will also automatically return an internal server error. If you're in debug mode this could be handy as you'd get the full Exception returned to you but if you return InternalServerError() you'd get no information even in debug and you'd have to check the logs...
In the ConfigureServices method of your Startup.cs class, inject your implementation of the IDbHero interface. Note this is a scoped service, meaning a new instance will be created for each HTTP request. Personally I never inject my Database access layer as a singleton because this could lead to some issues depending of the way this layer is implemented. For exemple EF Core's DbContext is incompatible with a singleton pattern.
services.AddScoped<IDbHero>(_ => new DBClass.HeroDb(Configuration.GetConnectionString("DbHeroConnectionString")));
I don't know how you handle the connection with the database because there's no mention of the connection string in your code example but I would do something like above.
Your connection string is coming from your appsettings.json config file
"ConnectionStrings": {
"DbHeroConnectionString": "YourConnectionString"
}
Now to use your mocked object in your unit test just do like this:
[TestMethod()]
public void ContactStatusList_ShouldReturnData_WhenCalled()
{
// ARRANGE
var mock = new Mock<IHeroDb>();
mock.Setup(x => x.GetList(DBClass.DBConstants.ListConstants.query_Contact_Status))
.Returns(CreateContactList());
var sut = new ListController(mock.Object);
// ACT
var result = sut.ContactStatusList();
// ASSERT
Models.Response response = (Models.Response)result;
Assert.AreEqual(response.Message, Models.ResponseMessages.Success);
Assert.IsNotNull(response.Data);
}
Notice few things here:
Your unit test name: This should show 3 things:
What you're testing (your method)
What should be the result (a result with data, a result with error, an exception raised...etc)
Under which conditions this result should happen
You can for exemple test that a method is returning an error when parameters have incorrect values. This should tested in another unit test
Unit tests are always in 3 parts ARRANGE, ACT and ASSERT. It's always a good practice to write that in each test so you can better organize your code
sut means System Under Test: this is what you want to test, all other dependencies (like your DbHero layer) should be mocked.
Now the next step would be to write a unit test to test your DbHero.GetList.
This time you'll create a real instance (not a mock) of the DbHero class because this is what you want to test: this is your sut.
Note that I've an intermediate level in testing so what I'm showing you is good practices I've learnt from my coworkers. But maybe some more experience developers could come up with better practices than mine.

Mock a method twice with NSubstitute to first throw error and later return value for the same called signature request

I wanted to mock a method twice with NSubstitute to first throw error and later return value for the same called signature request.
public interface IMyAction
{
public Task<MyDto> Upsert(CreateRequest requestDto);
}
public class MyAction : IMyAction
{
private readonly IMyRepository _repository;
public MyAction(IMyRepository repository)
{
_repository = repository;
}
public Task<MyDto> Upsert(CreateRequest requestDto){
{
var domainEntity = await _repository.Get(requestDto.Param1);
if(domainEntity == null)
{
try
{
// try to create entity
}
catch(RecordExistsException) // Throws when another concurrent request creates the same entity. Need to test this catch block scenario
{
domainEntity = await _repository.Get(requestDto.Param1);
//
//...perform update operation using the domainEntity and requestDto
//
}
catch(Exception ex)
{
throw
}
}
}
}
I have an edge case where I want the first call should throw an exception and the second call should return dto. Both calls have the same value for the parameter.
I am using NSubstitute to mock the dependencies in xunit test.
My setup:
IMyRepository _repository = Substitute.For<IMyRepository>();
var myAction = new MyAction(_repository);
_repository.Get(Arg.Any<string>()).Throws<NotFoundException>();
_repository.When(x => x.Get(Arg.Is<string>(r => r == "id1")))
.Do(x => _repository.Get(Arg.Is<string>(r => r == "id1")).Returns(new MyDto()));
Expectation:
_repository.Get("id1").Throws<NotFoundException>(); // first call invocation
_repository.Get("id1").Returns(new MyDto()); // second call invocation
but when myAction.Upsert(new CreateRequest()); called the domainEntity gets returned in the first call rather throwing exception.
After digging deep into SO, I found one solution here.
For my case, I fixed the issue by mocking as below-
_repository.Get("id1").Returns(x => throw new NotFoundException(), x => new MyDto());
Returns() also supports passing multiple functions to return from, which allows one call in a sequence to throw an exception or perform some other action.

How to add an exception test for the below Http call that returns a json

[HttpPost]
[Route("TnC")]
public IHttpActionResult TnC(CustomViewModel myViewModel)
{
try
{
return Json(_Internal.TnC(myViewModel, LoggedInUser));
}
catch (BusinessException exception)
{
return Json(BuildErrorModelBase(exception));
}
}
Where the _Internal is a Service with a guaranteed 99.99% up-time and not formalized fault contract interfaces defined.
Exceptions which are handled in my application level(business layer level) as a BusinessException - root class
Where BusinessException is defined as follows
public class BusinessException : Exception
{
BusinessException()...
BusinessExceptionFoo()...
BusinessExceptionBar()...
//...
}
And the current test Method is
To do : Add Exception test
[TestMethod]
[ExpectedException(typeof(BusinessException),
"Not a valid Business Case")]
public void TnCTest()
{
var bookingService = myContainer.Resolve<mySvc>();
var controller = new LinkBookingController(mySvc, myContainer);
var expectedResult = controller.TnC(new myViewModel
{
...params
});
var actualResult = GetData<Result<myViewModel>>(expectedResult);
Assert.AreEqual(expectedResult, actualResult);
}
expectedResult==actualResult does not test the exception block of the code.
How do I construct a request that makes the service throw the exception other than manually removing the ethernet cable to get this specific type of server error.
The best I could come up with was
#if DEBUG && UnitTestExceptions
throw new BusinessException();
#endif
But there is gotta be a better option.
There are a few things of concern with the method under test.
It is mixing cross-cutting concerns in the action that should be refactored out into an ExceptionHandler. Chances are that piece of code is repeated many times in that controller and others like it (DRY).
public class WebApiExceptionHandler : ExceptionHandler {
public override void Handle(ExceptionHandlerContext context) {
var innerException = context.ExceptionContext.Exception;
// Ignore HTTP errors
if (innerException.GetType().IsAssignableFrom(typeof(System.Web.HttpException))) {
return;
}
if(innerException is BusinessException) {
context.Result = BuildErrorResult(exception);
return;
}
//...other handler code
}
IHttpActionResult BuildErrorResult(BusinessException exception) {
//... your logic here
}
}
The following extension method could be used to add the handler to the HttpConfiguration during startup which also assumes that the application is taking advantage of dependency inversion services.
public static HttpConfiguration ReplaceExceptionHandler(this HttpConfiguration config) {
var errorHandler = config.Services.GetExceptionHandler();
if (!(errorHandler is WebApiExceptionHandler)) {
var service = config.Services.GetService(typeof(WebApiExceptionHandler));
config.Services.Replace(typeof(IExceptionHandler), service);
}
return config;
}
Now that cross-cutting concerns have been dealt with the action becomes a lot simpler and easier to test. This is a simplified example of an ApiController
public class LinkBookingController : ApiController {
private IBookingService bookingService;
public LinkBookingController(IBookingService service) {
bookingService = service;
}
[HttpPost]
[Route("TnC")]
public IHttpActionResult TnC(CustomViewModel myViewModel) {
return Json(bookingService.TnC(myViewModel, User));
}
}
where IBookingService is defined as
public interface IBookingService {
BookingModel TnC(CustomViewModel viewModel, IPrincipal user);
}
Using a mocking framework like Moq an exception can be made to be thrown as needed.
[TestMethod]
[ExpectedException(typeof(BusinessException), "Not a valid Business Case")]
public void TnC_Should_Throw_BusinessException() {
//Arrange
var bookingService = new Mock<IBookingService>();
var controller = new LinkBookingController(bookingService.Object);
var viewModel = new myViewModel
{
//...params
};
bookingService.Setup(_ => _.TnC(viewModel, It.IsAny<IPrincipal>())).Throws<BusinessException>()
//Act
var expectedResult = controller.TnC(viewModel);
//Assert
//...the ExpectedException attribute should assert if it was thrown
}
To test how that exception can be handled do a unit test on the exception handler and not the controller as that is not the responsibility of the controller.
Try to keep controllers lean and focused on its UI concerns.
As Nkosi mentioned in his comment, what you need to do is add an interface to whatever type _Internal is so that your controller now depends on an interface as a contract, rather than the specific implementation.
Next, create a second constructor for your controller that accepts a IInternalService (whatever its called) and assigns that to _Internal. Your parameterless constructor can still assign whatever instance you're using now.
Now that you have this configuration (often called "poor mans dependency injection"), your unit test can create an instance of your controller passing in a different implementation of your service that throws an exception. You can do this by creating a new class, or you can do it dynamically using a library like Moq.
Hope that makes sense.

unit test exception handled by try catch

I have catered for the situation when a config key has not been set in my business logic as follows:
public class Presenter
{
private readonly IView view;
public Presenter(IView view)
{
this.view = view;
}
public void DoStuff()
{
try
{
String someKey = ConfigurationManager.AppSettings["SomeKey"].ToString();
if (string.IsNullOrEmpty(someKey))
{
throw new InvalidOperationException("SomeKey not set.");
}
// do stuff
}
catch (InvalidOperationException ex)
{
// provide view with friendly error
// log error
}
}
}
My attempt at testing that this error occurrs when the key is not set:
[TestMethod]
public void Presenter_DoStuff_Should_Throw_InvalidOperationException_When_SomeKey_Not_Supplied()
{
// Arrange
mockIView = new Mock<IView>();
presenter = new Presenter(mockIView.Object);
// Act
// Assert
// NUnit here as more precise
NUnit.Framework.Assert.Throws<InvalidOperationException>(() => presenter.DoStuff(), "SomeKey not set.");
}
How do I get my test to pass as it stands? It currently fails because the try-catch is swallowing the exception for logging purposes. The test passes without the try-catch. This is with the AppSettings["SomeKey"] manually set to empty string.
Secondly, how do I specify in the test that someKey in DoStuff is empty to actually test this situation without having to manually remove the key setting?
Any help is greatly appreciated as I'm new to unit testing.
First of all, your test is invalid by design because your method doesn't actually throw an exception to calling code. This is because you immediately catch and handle that exception. This is actually a very incorrect use of exceptions. There's no need to throw based on a condition and then immediately catch when all you logically need to do is check that condition. Something like this:
public void DoStuff()
{
var someKey = ConfigurationManager.AppSettings["SomeKey"];
if (string.IsNullOrEmpty(someKey))
{
// provide view with friendly error
// log error
return;
}
// do stuff
}
Now the question becomes... what are you testing? The actual business logic of this method is in:
// do stuff
So hopefully that's the critical focus of the testing. Now, in order to reach 100% code coverage, you do also need to test what's in that conditional block. In order to do that, you need to simulate the condition. However, you have an external dependency:
ConfigurationManager
In order to test the logic, you're going to need to mock that dependency. A general approach to this is to create a kind of wrapper object for the dependency. In this specific case it could be something as simple as:
public class ConfigurationWrapper
{
public virtual string SomeKey
{
get
{
return ConfigurationManager.AppSettings["SomeKey"];
}
}
}
This could be separate from the class that has DoStuff, or even nested within. Depends on where/how else you'd want to use it. And of course it can be extended to wrap other configuration dependencies. Then within the class which has DoStuff you'd create a property for this wrapper. Something like this:
private ConfigurationWrapper _config;
public ConfigurationWrapper Configuration
{
get
{
if (_config == null)
_config = new ConfigurationWrapper();
return _config;
}
set { _config = value; }
}
And use it in DoStuff():
var someKey = this.Configuration.SomeKey;
Now the dependency on ConfigurationManager is wrapped in a mockable object. So in your unit test you'd create a mock ConfigurationWrapper object and set it on the object being tested. Something like:
var mockConfig = new Mock<ConfigurationWrapper>();
presenter.Configuration = mockConfig;
You can set your mock to return either a valid value or an empty string for the .SomeKey property, depending on what any given test needs. And then you'd validate whatever side-effect is produced by the conditional statement. (The "friendly error message" and the "logging" I assume. Which may involve further mocks, I can't know at this time.)
Of course, to reach 100% coverage you'd also need to add another test for the default case of the wrapper when one isn't externally set. That should be a fairly simple test:
// arrange
// no mocks to set up
// act
var presenter = new Presenter(null);
// assert
Assert.IsNotNull(presenter.Configuration);

Detailed exception logging on wcf

Lately I am working on exception logging module of a WCF service. Unfortunately the service hasn't been introduced with unit tests, therefore there are many unexpected exceptions occurring. And so far I have accomplished to get the exceptions with interceptor aproach, by implementing IErrorHandler interface and tying it to the service interface with IServiceBehaviour. I liked this functionality very much actually. But it brought me into a next step of desire of getting the details of exception. Like on which line did the exception occurred?
I can satisfy this desire by 2 ways in my mind:
By having a variable for keeping track of the lines I've passed through successfully, and including it in the exception thrown.
By catching exceptions from all lines seperately.
But both approaches seem very lousy to me. I am wondering is there a known design pattern or a tool to achive this goal?
In my opinion you might try using logging, such as log4net. Then you can find out where is and what happened. Exception object not always contains the stack info, because of "inlining", that occur during optimization etc.
include the PDB files for your service and the line numbers will be included in exception.ToString()
The way we have solved this problem is twofold:
Our services are dumb wrappers around commands. So when a service method is entered it delegates its work to a command.
We wrap every command call in a logging proxy that is responsible for logging input, output and errors and executing the command.
For example:
public FooServiceModel GetFoo(int fooId)
{
return new ILogged<GetFooCommand>().Target.Execute(fooId);
}
This delegates execution of the command to ILogged which:
Logs the command name
Logs the command parameters
Logs the execution result
Logs any exceptions
It also does some other stuff to link up the client request with the server call using custom message headers so that a call can be completely debugged from client to server and back. This is incredibly useful and allows us to diagnose even complex problems off site.
We use the Castle.Core dynamic proxy to implement ILogged with an interceptor that looks something like this (ILog is a log4net logger):
public class LoggingInterceptor : IInterceptor
{
public LoggingInterceptor([NotNull] object target, [NotNull] ILog logger)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (logger == null)
{
throw new ArgumentNullException("logger");
}
this.Target = target;
this.Logger = logger;
}
public object Target { get; set; }
public ILog Logger { get; set; }
public void Intercept(IInvocation invocation)
{
try
{
this.Logger.Debug(invocation);
invocation.ReturnValue = invocation.Method.Invoke(
this.Target, invocation.Arguments);
this.Logger.Debug("Invocation return value:");
this.Logger.Debug(invocation.ReturnValue);
}
catch (TargetInvocationException ex)
{
this.Logger.Error("Unable to execute invocation", ex);
if (ex.InnerException != null)
{
throw ex.InnerException;
}
throw;
}
}
}
The invocation itself is rendered by a custom log4net object renderer:
public class InvocationRenderer : IObjectRenderer
{
public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
{
var invocation = (IInvocation)obj;
var builder = new StringBuilder();
builder.AppendFormat(
"Invoking Method: {0} --> '{1}' with parameters (",
invocation.Method.DeclaringType != null
? invocation.Method.DeclaringType.FullName : "{Unknown Type}",
invocation.Method);
var parameters = invocation.Method
.GetParameters()
.Zip(invocation.Arguments, (p, a) => new { Parameter = p, Argument = a })
.ToArray();
var index = 0;
foreach (var parameter in parameters)
{
builder.AppendFormat(
"{0}: {1}",
parameter.Parameter.Name,
rendererMap.FindAndRender(parameter.Argument));
if (++index < parameters.Length)
{
builder.Append(", ");
}
}
builder.Append(")");
writer.Write(builder.ToString());
}
}
Hopefully that will give you some ideas on how to tackle this problem.

Categories