Click here to Skip to main content
15,867,453 members
Articles / Web Development / HTML

Mocking External WCF Service in MVC Controller - Using Unity Dependency Injection

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
21 Jul 2014CPOL4 min read 20.3K   270   22   1
Mock (moq) your service in your MVC controller

Introduction

Download WcfUnity.zip (VS2013)

I have removed all the NuGet packages and the bin dll's from the zipped download for compactability reasons. But, when you compile the project - the solution will download all the respective assemblies from NuGet. I am using Visual Studio 2013, but you can use VS2012 Web Express upwards.

Background

When unit testing your controller method, you want to mock out the layers that your code communicates with. This can be easily done using mocking frameworks like RhinoMock or MOQ. It's always the first and last layer that cannot be mocked, as you do not have mocking control over the UI (first layer) or the external service or database procedure (last layer), for example. For these scenarios, you will use integration testing tools like Selenium or CodedUI to perfrom that end-2-end testing (UI through to service\database).

But, there are scenarios when you second last layer needs to be mocked out, but your control over it again is limited, as it maybe deployed onto a server and your application is consuming it - for example a soap services that communicates with and external database or performs some number crunching logic. In your unit test you are only concerned with the logic inside the controller method not the service - thus, you would like to mock the service call, as the service will have already been unit tested before it's deployment. 

IOC & Project Structure

For my IOC  container, I am going to be using the MVC.Unity 4 Nuget package. My test project is split up into three projects:

  1. WCF service project
  2. MVC web application
  3. Test project

Image 1

Code Explanation

For simplicity sake, I have setup up the Unity Resolver within the Application_Start method within the Global.asax class (a better approach is to create a static BootStraper method and call that from Application_Start - making the code more maintainable - as this method, overtime in a normal application will become code congested).

Before I add the Unity Resolver code, you will want to consume your externall service into your project. In my case I deployed StockServices to my local IIS and then consumed the WSDL into my project as normal.

Image 2

C#
protected void Application_Start()
        {           
            var container = new UnityContainer();
            container
                .RegisterType<IStock, StockClient>()
                .Configure<InjectedMembers>()
                .ConfigureInjectionFor<StockClient>(new InjectionConstructor("*"));
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));

        }

 

The snippet of code above is very standard for resolving an interface to a concrete class. The only thing of interest is where do I get the service name - StockCleint from?

If you double click on your service refernce within your project, the Object Browser window will open and you can scroll down to the service entry - the service name will always have a postfix of Client. This is the concrete class name you want your service interface to resolve to.

Image 3

Now that you know where and how-to resolve your service dependencies. the next section is how do I inject the service into my Controllers, and then execute the service methods after Constructor injection.

 

Controller Code

In the snippet of code below, there are a couple lines of code that we are interested in. Namely, the constructor injection of our interface IStock and the private variable stock. Only from MVC 3 has it been possible to create a controller class with a constructor. Thus, we can use Unity's Constructor Dependency Injection approach, to implement our concrete class through the constructor.

Injecting a service into your controller is now very easy and making the service method calls is also straight forward - but the important thing to note is that you are dependency injecting your interface, and thus you will be able to mock your interface at a later date in your tests. For simplistic reasons, I am just calling the service to bring back a data type and a class structure. 

C#
public class HomeController : Controller
   {
       private readonly StockService.IStock stock;

       public HomeController(StockService.IStock stk)
       {
           stock = stk;
       }

       public ActionResult Index()
       {
           ViewBag.Message = stock.GetData(10);

           return View("Index");
       }

       public ActionResult About()
       {
           StockService.StockData data = stock.GetStockData();
           ViewBag.Message = String.Format("Your stock {0} has a value {1}.", data.StockName, data.StockValue);

           return View("About", data);
       }
   }

Creating Tests

The hard part is already done, as we simply create our unit tests as normal, mocking out the service and it's methods. We inject the mock service into the controller constructor that we are looking to test, then test the controller method as normal. In the tests below I simply test the mocked Model or ViewBag, but you might want to use MVC helpers to test the html being generated etc.

C#
[TestClass]
    public class HomeControllerTest
    {
        [TestMethod]
        public void Index()
        {
            // test variables
            string expectedViewName = "Index";
            string returnValue = "300";

            // mocking objects
            Mock<IStock> mockIStock = new Mock<IStock>();
            mockIStock.Setup(t => t.GetData(It.IsAny<int>())).Returns(returnValue);

            // Arrange
            HomeController controller = new HomeController(mockIStock.Object);

            // Act
            ViewResult result = controller.Index() as ViewResult;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(result.ViewBag.message, returnValue);
            Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName);
        }

        [TestMethod]
        public void About()
        {
            // test variables
            string expectedViewName = "About";
            string stockName = "BON";
            double stockValue = 1;

            // mocking objects
            Mock<StockData> mockStockData = new Mock<StockData>();
            mockStockData.Object.StockName = stockName;
            mockStockData.Object.StockValue = stockValue; // penny stock :)

            Mock<IStock> mockIStock = new Mock<IStock>();
            mockIStock.Setup(t => t.GetStockData()).Returns(mockStockData.Object);

            // Arrange
            HomeController controller = new HomeController(mockIStock.Object);

            // Act
            ViewResult result = controller.About() as ViewResult;

            // Assert            
            Assert.IsNotNull(result);
            Assert.IsTrue(result.ViewBag.message == String.Format("Your stock {0} has a value {1}.", stockName, stockValue));
            Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName);
            Assert.AreEqual(result.Model, mockStockData.Object, "Model should have been {0} and {1}", mockStockData.Object.StockName, mockStockData.Object.StockValue);
        }
    }

Running Tests

To run the tests within VS2012\13, simply right click your test class and select Run Tests from the context menu, this will then display the results of your tests - you can insert a breakpoint and debug as normal through your tests.

Image 4

 

Image 5

Conclusion

Mocking external service is extremely easy, there is a little extra step when working with  dynamically built up service endpoints - but again you would just use the endpoint details (for example, WSHttpBinding_IStock) as your resolving concrete class when lazy loading a service.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Ireland Ireland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralThanks for the code Pin
Member 1132443819-Dec-14 22:04
Member 1132443819-Dec-14 22:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.