How to Mock for Unit Testing
I have got the discussion with my colleague about unit testing with some scenario that his/her target function will involved into others teams APIs but not ready yet. But he/she already completed the logic of demand function(s) and want to validate with unit testing and perform integration test later after every all settle down.
We think that for the case we could introduce some mock service(s) for the current stage to accomplishment the unit test and verify the logic from our end merely.
The story will demonstrate the simply example that how to adopt mock concept into the case and so that we could focus and control the development process in the easy approach😊.
Suppose we have implemented the shopping cart service with following steps:
- Ensure user in login status.
- Ensure the item(s) amount of stock on hand.
- Calculate totals amount for the item(s).
- Select available payment gateway.
- Validate the payment status.
- Others…..
And for the payment affairs, we might need to connected to others team’s (or third party(s)) API for completed the payment process and check out process for the deal.
According above scenario that we have simply the below interface, we need implement ICartService for the function of Checkout. and we will inject IPaymentService for handling payment relative processes.
public interface IPaymentService
{
ResultModel Pay(List<Item> Items);
}public interface ICartService
{
ResultModel Checkout(List<Item> Items);
}
So the pseudo code might look as below:
public class CartService : ICartService
{
private readonly IPaymentService _paymentService;
public CartService(IPaymentService paymentService)
{
_paymentService = paymentService;}
public ResultModel Checkout(List<Item> items)
{
// check user status and inventory status
// ...
// everything would looks fine, invoke payment service
var payResult = _paymentService.Pay(items);
// so far if pay result was completed then
// inform warehouse and packing to the rest of processes
// ... }}
Next, we create the Microsoft unit test project (see guide here) and installed the mock library: moq that help us setup mock service for payment.
[TestClass]
public class ECServiceUinitTest
{
private ICartService _cartService;
private Mock<IPaymentService> _mockPaymentService; [TestInitialize]
public void Initialize()
{
// config model
var configModelOptions = new ConfigModel()
{
ApiKey = "....", };
// new mock object for IPaymentService
_mockPaymentService = new Mock<IPaymentService>(MockBehavior.Strict); // new cart service and passing config model
// and mock object for DI
_CartService = new CartService(configModelOptions, _mockPaymentService.Object); } [TestMethod]
// Test for checkout function with success case
public void Test_Checkout_Cart_Return_Success()
{
// arrange
var item1 = new Item() {Name = "IPhone12", Price = 1000}; var item2 = new Item() {Name = "IWatch6", Price = 500}; var items = List<Item>() {item1, item2};
// setup mock method: Pay to return success for any input
// so that we could focus testing our cart service
_mockPaymentService.Setup(e => e.Pay(It.IsAny<List<Item>>())).Returns(
new ResultModel()
{
Status = "Success"
}); // actual
var result = _cartService.Checkout(items).GetAwaiter().GetResult(); // assert
Assert.AreEqual("Success", result.Status);
}}
As the example demonstrate that we could easily setup the behavior of mock object for different test case(s). No matter for the normal successful flow or any edge cases (even failed scenario).
I’m not a great programmer; I’m just a good programmer with great habits. ― Kent Beck
Writing a unit test is a great habits and also a way to solid your application as well😃.