Mocking Exceptions

When writing unit tests, it is important to cover not only the successful execution path (commonly referred to as the “Happy” path), but also test the code that gets executed when things don’t go right (commonly referred to as the “Unhappy” path). Testing for situations where services or databases are unavailable as well as erroneous user input are important aspects of ensuring quality in software. Remember, if you don’t test it, your users will!

We modify the LoginUser method to throw a custom exception when there is an exception is thrown from the LoginService. To test this, we need to be able to throw an exception from our mock, and test for the custom exception in the unit test.

public bool LoginUser(string userName, string password)

{

try

{

UserID = _service.ValidateUser(userName, password);

}

catch (Exception ex)

{

thrownew MyServiceException(ex.Message);

}

if (UserID != 0)

{

ShoppingCart = _cartRepo.LoadCart(UserID);

returntrue;

}

returnfalse;

}

This is extremely simple with JustMock and NUnit. In the following test, we setup an expectation that the code will throw a custom exception (of type MyServiceException) and the message in the exception will be “Unable to contact the Login Service”.

We then arrange the mock of the ILoginService to throw a system exception with the message that we are expecting, including the message for the exception. We can then validate that our line of business code behaves exactly as expected when all does not go as planned.

[Test,

ExpectedException(typeof(MyServiceException),

ExpectedMessage = "Unable to contact the Login Service")]

public void Should_Throw_An_Exception_With_Negative_Parameter()

{

ILoginService service = Mock.Create<ILoginService>();

Mock.Arrange(() => service.ValidateUser(string.Empty, string.Empty))

.IgnoreArguments()

.Throws<System.Exception>("Unable to contact the Login Service");

SecurityHandler handler = new SecurityHandler(service, null);

handler.LoginUser("foo", "bar");

}

Mocking Events

Handling events in your system under test can be tricky. Suppose your service raises an event, and you want to log that event (for example to track when user’s have logged on). Normally, you would probably log this to an event log or some other tracking mechanism, but for the sake of simplicity, we are just going to use a struct to represent the logging. The new SecurityHandler and the UserLoginEventLog struct look like this :

The security handler subscribes to the event on the ILoginService, and when the event fires, populates the struct with the data from the event.

We add an event to the ILoginService interface and create a custom EventArgs class to pass the data to the listener:

publicinterface ILoginService

{

int ValidateUser(string userName, string password);

event UserLoggedOnEventHandler UserLoggedOnEvent;

}

publicdelegate void UserLoggedOnEventHandler(

object sender, UserLoggedOnEventArgs eventArgs);

publicclass UserLoggedOnEventArgs : EventArgs

{

publicstring UserName { get; set; }

public DateTime TimeLoggedOn { get; set; }

public int UserID { get; set; }

public UserLoggedOnEventArgs(

string userName, DateTime timeLoggedOn, int userID)

{

this.UserName = userName;

this.TimeLoggedOn = timeLoggedOn;

this.UserID = userID;

}

}

To validate our system under test, we inject the appropriate mock objects, and arrange the appropriate methods. We don’t need to arrange the call on the ShoppingCartRepository since we are ok with it returning null (remember, a loose mock returns the default value for any method not arranged).

It is important to call Mock.Raise after the instantiation of the security handler since the even is subscribed to in the constructor. Otherwise we get a null reference exception. We can then verify that the event was raised, and our code correctly assigns the values from the event args into the struct representing our event log.

The astute reader will notice that we can comment out the call to handler.LoginUser(userName, password) and the test will still pass. That is because the call to Mock.Raise unconditionally raises the event.

Fortunately, JustMock provides another version, the Raises() extension method on the Arrange. This allows you to specify an event that is raised after a method is called. The significant change in the following test is highlighted in yellow. The call to Mock.Raise is removed, and is moved to the Arrange code block. This tells the JustMock framework to raise the event after the ValidateUser method is called, which is the expected behavior of our line of business code.