Unit Test Through Mocking Using MOQ Framework

I am going to demonstrate the use of a very popular mocking framework, MOQ, to mock the database/service calls.
The example in the article is an Order Processing class, mimicking the order processing system. The business logic in this class is to fetch an order from a database (by order Id), adding 10% GST on the amount, and then saving it back to the database.
To test this business logic, I will be writing a unit test. The unit test will have the Order Id as an input, so it can fetch the order from the DB (as database fetch and save is part of business logic).
However, we have some trouble if we were to write a unit test case…
  1. If we fetch and assert some predetermined output from a DB, it probably will be successful first time because the second time, the data will be changed.
  2. DB may or may not be online at the time of the test.
  3. It is strictly no-no to run this unit test in UAT or Prod environment, as it should not be manipulating the data.
So, the question is do we really need to fetch the data from DB to test business logic? Well, the answer is "No".
For argument (the example I considered) you might want to say, “move the DB operation to separate methods”. Yes, you are absolutely right in this instance, however, my focus is to demonstrate the capability of mocking.
Alright. too much talk; let’s get into some action.
Here is my “OrderProcessing” class. Here I am fetching record from database, calculating total amount by adding 10% GST on the order amount and saving it back to database.
  1. public class OrderProcessing  
  2. {  
  3.     // object responsible for database operation  
  4.     DBContext dbContext = new DBContext();  
  6.     public Order ProcessGSTForNextOrder(int orderId)  
  7.     {  
  8.         var nextOrder = dbContext.GetNextOrderDetailFromDB(orderId);  
  10.         nextOrder.Amount = CalculateTotalAmountWithGST(nextOrder);  
  12.         dbContext.SaveOrder(nextOrder);  
  14.         return nextOrder;  
  15.     }  
  17.     public decimal CalculateTotalAmountWithGST(Order order)  
  18.     {  
  19.         return order.Amount + (order.Amount * (10 / 100));  
  20.     }  
  21. }  
The unit test generally looks like this.
  1. [TestMethod]  
  2. public void TestOrderProcessing()  
  3. {  
  4.     var dummyOrderId = 1234;  
  5.     OrderProcessing orderProcessing = new OrderProcessing();  
  6.     var modifiedOrder = orderProcessing.ProcessGSTForNextOrder(dummyOrderId);  
  8.     Assert.IsTrue(modifiedOrder.Amount == 1000);  
  9. }  
Now to demonstrate the power of mocking through MoQ I will tweak the unit testing.
First, I need to create an interface named IDBcontext. Instead of creating an object of DBContext at the class level, I will be injecting IDBContext in “ProcessGSTForNextOrder” method along with the order id.
You might be wondering why we created an interface. Well, the answer is - if we need to mock any method, it should be a part of the interface. In this instance, we will be mocking two methods - “GetNextOrderDetailFromDB” and “SaveOrder”. So I made them part of interface. Rest of the functionality remains same.
  1. public interface IDBContext  
  2. {  
  3.     Order GetNextOrderDetailFromDB(int orderID);  
  5.     void SaveOrder(Order nextOrder);  
  6. }  
  8. public class OrderProcessingWithMoq  
  9. {  
  10.     public Order ProcessGSTForNextOrder(IDBContext dbContext, int orderId)  
  11.     {  
  12.         var nextOrder = dbContext.GetNextOrderDetailFromDB(orderId);  
  14.         nextOrder.Amount = CalculateTotalAmountWithGST(nextOrder);  
  16.         dbContext.SaveOrder(nextOrder);  
  18.         return nextOrder;  
  19.     }  
  21.     public decimal CalculateTotalAmountWithGST(Order order)  
  22.     {  
  23.         return order.Amount + (order.Amount * 10 / 100);  
  24.     }  
  25. }  
Now, let’s look into our modified unit test case.
  1. [TestMethod]  
  2. public void TestOrderProcessing()  
  3. {  
  4.         int orderId = 1234;  
  6.         Mock<IDBContext> mockDBContext = new Mock<IDBContext>();  
  8.         mockDBContext.Setup(t => t.GetNextOrderDetailFromDB(It.IsAny<int>())).Returns(new Order() { OrderId = orderId, Amount = 1000 });  
  9.         mockDBContext.Setup(t => t.SaveOrder(It.IsAny<Order>()));  
  11.         OrderProcessingWithMoq orderProcessing = new OrderProcessingWithMoq();  
  12.         var modifiedOrder = orderProcessing.ProcessGSTForNextOrder(mockDBContext.Object, orderId);  
  14.         Assert.IsTrue(modifiedOrder.Amount == 1100);  
  15.  }  
I will explain one by one, use of each statement.
First have created a mocking object of DBContext by this statement. This statement says we will be potentially mocking a few methods or properties of the interface or System Under Test (SUT)
  1. Mock<IDBContext> mockDBContext = new Mock<IDBContext>();  
Once the mocking object is ready, I will be mocking two methods.
Here I have set up if this method gets executed through mocking object, then for “any” integer (in this case order id), it returns an order object with the amount 1000 and order id setup.
  1. mockDBContext.Setup(t => t.GetNextOrderDetailFromDB(It.IsAny<int>())).Returns(new Order() { OrderId = orderId, Amount = 1000 });  
Similarly, “SaveOrder” has been mocked for “any” order passed.
  1. mockDBContext.Setup(t => t.SaveOrder(It.IsAny<Order>()));  
By mocking these two methods, I ensured it will not hit the database.
The “orderProcessing” object will have the mocking IDBContext object injected.
  1. var modifiedOrder = orderProcessing.ProcessGSTForNextOrder(mockDBContext.Object, orderId);  
The flow will go on from here, executing and returning dummy orders; and I can ensure the business logic for calculating GST is working correctly.
  1. Assert.IsTrue(modifiedOrder.Amount == 1100);  
Happy TDD.