If you are bit
experience in software development mainly Test Driven Development then you might
familiar with those concepts. As this article is not dedicated to discuss mocking,
we will very quickly cover the concept and then we will see how mocking can
help us in application development.
We know that mocking is
something which replaces the actual activity. In software development, there
might be situation, where one component is dependent on another component and the
dependent component is need to develop at first , in this situation we can
implement mock object which will mimic the original functionality.
Mainly in case of Test
Driven Development, people write test case at first and the code and we know
that,in application one component is dependent on many components, this is the
perfect scenario where concept of mocking comes into picture.
To implement mocking,
there are many frameworks available, Moq is one of them. It’s free and simple
to use. In this article we will see how Moq can use to implement mocking. Point
to say that, mocking gets dramatically easy once we inject dependency in class,
In this example we have implemented constructor injection to inject dependency.
First of all just give
reference of Moq from Nuget package manager to your Unit test project, if you
are using visual Studio or you an individually download the Moq dll and give
reference to your project.
Once you give
reference, you will find the dll in reference directory. Fine, we have done our primary setup. Now,
let’s implement the below code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
public interface IService
{
Boolean Call();
}
public class Service : IService
{
public Boolean Call()
{
throw new Exception();
}
}
public class MockTest
{
public readonly IService _service = null;
public MockTest(IService tmpService)
{
_service = tmpService;
}
public Boolean Execute()
{
if (_service.Call())
return true;
else
return false;
}
}
}
The class is extremely simple, Just we have implemented
Iservice interface in Service class and MockTest class has Execute function
which we will mock using Moq framework. Now, we will implement code for unit
test.
[TestClass]
public class MVCUnitTest
{
[TestMethod]
public void Mock_To_Service_function_Returns_True_always()
{
var mock = new Mock<IService>();
mock.Setup(x => x.Call()).Returns(true);
var MockTestObject = new MockTest(mock.Object);
Assert.AreEqual(MockTestObject.Execute(),
true);
}
}
Here is the output of unit test, we are seeing that the test
got pass. Because in mock object we have setup Call() function ,in such a way
that it will always return true in time
of call. In face the mocked function will not even call in time of execution.
So, we have learned how to set simple return type of a
function. In need we can set out custom
data as returned type from mocked function. Have a look one below example.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
public interface IUsersInfo
{
List<UsersInfo> GetUsers();
}
public class UsersInfo : IUsersInfo
{
public string username{get;set;}
public string password {get;set;}
public List<UsersInfo> GetUsers()
{
//It should return below data
//return new List<UserInfo>
//{
// new
UserInfo{username="foo",password="foo"},
// new
UserInfo{username="sourav",password ="kayal"}
//};
throw new NotImplementedException();
}
}
public class MockTest
{
public readonly IUsersInfo _userinfo = null;
public MockTest(IUsersInfo TmpUser)
{
_userinfo = TmpUser;
}
public List<UsersInfo> GetUser()
{
return _userinfo.GetUsers();
}
}
}
The GetUsers() function should return a list of UserInfo
class , but since it still not implemented we will throw exception in this
function intentionally and we will mock the output of the function in time of
Unit test to make our unit test pass. Here is the code for unit test.
using System;
using ConsoleApp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using ConsoleApp;
using System.Collections.Generic;
namespace TestMVC
{
[TestClass]
public class MVCUnitTest
{
List<UsersInfo> UserInfo
= null;
[TestInitialize]
public void InitializeTest()
{
//Create mock return object
UserInfo = new List<ConsoleApp.UsersInfo>
{
new UsersInfo{username="foo",password="foo"},
new UsersInfo{username="sourav",password ="kayal"}
};
}
[TestMethod]
public void Mock_To_Service_function_Returns_True_always()
{
var mock = new Mock<IUsersInfo>();
//Setup return data of Mock function
mock.Setup(x => x.GetUsers()).Returns(UserInfo);
var MockTestObject = new MockTest(mock.Object);
Assert.AreEqual(MockTestObject.GetUser(),
UserInfo);
}
}
}
And once we run the test , we will see that the test got
pass.
Now, in our previous example we have mocked single interface
but in need you can mock multiple interface and inject the mocked object as
parameter of constructor. In this example we will see how we can mock multiple
objects. Here is the class
implementation.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
public interface IUsersInfo
{
List<UsersInfo> GetUsers();
}
public interface IUserInfoById
{
UsersInfo GetUserById(int Id);
}
public class UsersInfo : IUsersInfo , IUserInfoById
{
public string username{get;set;}
public string password {get;set;}
public List<UsersInfo> GetUsers()
{
//It should return below data
//return new List<UserInfo>
//{
// new
UserInfo{username="foo",password="foo"},
// new
UserInfo{username="sourav",password ="kayal"}
//};
throw new NotImplementedException();
}
public UsersInfo GetUserById(int Id)
{
throw new NotImplementedException();
}
}
public class MockTest
{
public readonly IUsersInfo _userinfo = null;
public readonly IUserInfoById _userinfoById = null;
public MockTest(IUsersInfo TmpUser, IUserInfoById TmpUserById)
{
_userinfo = TmpUser;
_userinfoById = TmpUserById;
}
public List<UsersInfo> GetUser()
{
return _userinfo.GetUsers();
}
public UsersInfo GetUserById(int Id)
{
return _userinfoById.GetUserById(Id);
}
}
}
We are seeing that there are two interfaces which two
different classes has implemented, and through constructor of MockTest class we
will inject dependency by mocked objects. Here is the code for Unit test.
using System;
using ConsoleApp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using ConsoleApp;
using System.Collections.Generic;
namespace TestMVC
{
[TestClass]
public class MVCUnitTest
{
List<UsersInfo> UserInfoList
= null;
UsersInfo UserInfo = null;
[TestInitialize]
public void InitializeTest()
{
//Create mock return object
UserInfoList = new List<ConsoleApp.UsersInfo>
{
new UsersInfo{username="foo",password="foo"},
new UsersInfo{username="sourav",password ="kayal"}
};
UserInfo = new ConsoleApp.UsersInfo {
username = "sourav",
password = "kayal"
};
}
[TestMethod]
public void Mock_To_Service_function_Returns_True_always()
{
var mockUser = new Mock<IUsersInfo>();
var mockUserbyId = new Mock<IUserInfoById>();
//Setup return data of Mock function
mockUser.Setup(x => x.GetUsers()).Returns(UserInfoList);
mockUserbyId.Setup(x => x.GetUserById(1)).Returns(UserInfo);
var MockTestObject = new MockTest(mockUser.Object,mockUserbyId.Object);
Assert.AreEqual(MockTestObject.GetUser(),
UserInfoList);
Assert.AreEqual(MockTestObject.GetUserById(1),
UserInfo);
}
}
}
And we are seeing that the test got pass because we have
created two mock objects one is mockUser and mockUserById, then we save
configured two functions by calling Setup() method of mock object.
Border line:-
Hope you have understood the concept of mocking using Moq
framework, In another article I am interested to show various functionality of
Moq framework. It’s not that Moq is the best one , few other frameworks like
Type Mock etc, gives more functionality then Moq and other free framework. But I
think for small and mid size of project with less complexity, those free
framework work fine.
No comments:
Post a Comment