Read More on Telerik Blogs
January 27, 2012 Productivity, Testing
Get A Free Trial

How you assert through unit test that an user is authenticated before doing withdraw operation? You can surely verify a method is invoked as expected but if you want to ensure the order right then you might require a little more. JustMock lets you specify the order in which your setups should be executed. This helps you identify the exact way in which a particular logic is implemented.

To begin, lets consider the following context:

User wants to withdraw money from his account. Withdraw operation should validate the following goals:

  • It should check if the user is authenticated
  • It should get the balance for the authenticated user and check if the amount to be withdrawn is less than or equals to what is specified.
  • Do the withdraw operation and return the remaining balance.

Now we have one IUserService interface

  1. public interface IUserSerivce
  2. {
  3.     bool IsAuthenticated { get; }
  4.     IUser GetUser();
  5.  
  6. }

One IAccountService interface to process the accounts operation:

  1. public interface IAccountService
  2. {
  3.     double Withdraw(double amount);
  4.     double GetBalance(IUser user);
  5. }

The basic AccountRepository class with minimal implementation covering the above context looks like:

 

  1. public class AccountRepsotory
  2. {
  3.     public AccountRepsotory(IUserSerivce userService, IAccountService accountService)
  4.     {
  5.         this.userService = userService;
  6.         this.accountService = accountService;
  7.     }
  8.  
  9.     public virtual double Withdraw(double amount)
  10.     {
  11.         if (userService.IsAuthenticated)
  12.         {
  13.             if (accountService.GetBalance(userService.GetUser()) >= amount)
  14.             {
  15.                 return accountService.Withdraw(amount);
  16.             }
  17.         }
  18.  
  19.         throw new ArgumentException("TODO");
  20.     }
  21.  
  22.     private readonly IUserSerivce userService;
  23.     private readonly IAccountService accountService;
  24. }

Ensuring every step to be executed in an orderly manner , we just need to specify an extra InOrder option in Mock.Arrange that will otherwise fail the test during assert for any change of the expected execution order.

  1. [TestMethod]
  2. public void ShouldCheckUserAndBalanceInOrderWhenSpecificAmountIsWithdrawn()
  3. {
  4.     var userService = Mock.Create<IUserSerivce>();
  5.     var accountService = Mock.Create<IAccountService>();
  6.     
  7.     var user = Mock.Create<IUser>();
  8.  
  9.     Mock.Arrange(() => userService.IsAuthenticated).Returns(true).InOrder();
  10.     Mock.Arrange(() => userService.GetUser()).Returns(user).InOrder();
  11.     Mock.Arrange(() => accountService.GetBalance(user)).Returns(1000).InOrder();
  12.  
  13.     Mock.Arrange(() => accountService.Withdraw(Arg.AnyDouble)).Returns((amount) => 1000 - amount).InOrder();
  14.  
  15.  
  16.     var repository = new AccountRepsotory(userService, accountService);
  17.  
  18.     Assert.AreEqual(990, repository.Withdraw(10));
  19.  
  20.     Mock.Assert(userService);
  21.     Mock.Assert(accountService);
  22. }

Let’s remove the line# 13 from AccountRepository.Withdraw  that yields:

  1. public virtual double Withdraw(double amount)
  2. {
  3.     if (userService.IsAuthenticated)
  4.     {
  5.         return accountService.Withdraw(amount);
  6.     }
  7.  
  8.     throw new ArgumentException("TODO");
  9. }

 

 

Since we broke the order, the test will fail with the following message:

 

Here one thing to notice that InOrder is applied to different mock instances within the test method scope that makes it effective in most practical and wide variety of scenarios. I have used Q3 SP build for the purpose (Also available via NuGet).

 

Hope that helps