Monday, 28 April 2014

Writing Unit Test Method for Web API Controllers and Generic Repository Using Moq

In my previous post I have shown how to mock a generic repository. In this post I want to show the same can be done using Moq in a much simpler way. One of the limitations that is having in the approach I mentioned earlier is the difficulties in manipulating mock data as required by the test method. In this approach we can still get the basic set of data from a helper class but we modify them further to suit our requirement for a particular test method.  We can then set up the repository method using Moq framework to return required data. You can get the latest Moq framework using "Manage NuGet Packages" from Visual Studio.

Let us now consider the following implementation for testing a controller say EmployeeController.

 --------------------------------------------------------------------------------------------------------------------------
   public class EmployeeControllerTest
    {
        Mock<PeerFeedbackEntities> context;
        Mock<MockUnitOfWork> unitOfWork;


        [TestMethod]
        public void GetEmployeeByDesignationTestTest()
        {
            context = new Mock<PeerFeedbackEntities>();
            unitOfWork = new Mock<MockUnitOfWork>(context.Object);
           
            EmployeeController controller = new EmployeeController(unitOfWork.Object);


            controller.Request = new HttpRequestMessage(HttpMethod.Post, http://localhost:9153/api/GetEmployeeDetailByDesignation/?designationId=1);

            controller.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());


            var result = controller.GetEmployeeDetailByDesignation(1);
            var data = result.Content.ReadAsAsync<List<Employee>>().Result;


            Assert.AreEqual(System.Net.HttpStatusCode.OK, result.StatusCode);
            Assert.AreEqual(1, data.Count);
        }

    }
--------------------------------------------------------------------------------------------------------------------------
 
In the above class we are using Moq to create mock instances of our required classes. This enables us to avoid the execution from real repository methods and instead will execute the mock methods of the mock repository at runtime. The method also whows how to test a controller method.
 
Now we have two things here to consider. The above approach requires us to create a mock repository against a real repository. It can be a bit time consuming. Also second big disadvantage is the control over the mock data returned from the repository. We will face problem or unnecessary additional effort if we want to return specific data for particular test methods from repositories.
 
Let us consider the below implementation of the same test method.
--------------------------------------------------------------------------------------------------------------------------
    [TestClass]
    public class EmployeeControllerTest
    {
        Mock<PeerFeedbackEntities> context;
        Mock<IUnitOfWork> unitOfWork;
 
        [TestMethod]
        public void GetEmployeeByDesignationTestTest()
        {
            context = new Mock<PeerFeedbackEntities>();
            unitOfWork = new Mock<IUnitOfWork>();
 
            EmployeeController controller = new EmployeeController(unitOfWork.Object);
 
            //Get the mock data
            var employies = MockDataProvider.GetEmployees();
            employies.RemoveAt(1);

            //Manipulate it accordingly           
            employies[0].DateOfBirth = new DateTime(1980, 10, 13);

           //Setup the repository method to return the above collection when the method GetEntity(Expression<Func<TEntity, bool>> filter, List<string> relatedEntities) is executed
            unitOfWork.Setup(m => m.EmployeeRepository.GetEntity(It.IsAny<Expression<Func<Employee, bool>>>(), It.IsAny<List<string>>())).Returns(employies.AsQueryable());

            controller.Request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:9153/api/GetEmployeeDetailByDesignation/?designationId=1");

            controller.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

            var result = controller.GetEmployeeDetailByDesignation(1);
            var data = result.Content.ReadAsAsync<List<Employee>>().Result;
 
            Assert.AreEqual(System.Net.HttpStatusCode.OK, result.StatusCode);
            Assert.AreEqual(1, data.Count);
        }
    }
 
--------------------------------------------------------------------------------------------------------------------------
In the test method in the above class we are not using Mock Repositories. Instead we are mocking a IUnitOfWork instance and then setting up its repository properties to return the set of data we want to return. This not only reducing our effort of mocking each single repository but also helping us returning mock data from the generic methods as required for a particular scenario.
 
We can also setup the methods to return data against a specific set of parameters. There are many example in the net that shows how to set up Moq to return desired mock data.
 
To see the actual code of the above implementation, check here
  

No comments:

Post a Comment