Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Mock & Inject your Service with Moq and Ninject

0.00/5 (No votes)
10 Aug 2016 1  
Design your solution and code your classes as loosely-coupled objects. Learn how to use MOQ and Ninject for mocking your Service and injecting it at runtime with Ninject.

Introduction

Lately, I have been struggling with a problem related to solution design. I have been working at product development rather than on a project itself, and specifically on the front-end side.

It happened that I needed to test components binding, but since the WebService was not ready yet, I had only the service specifications in my hand.

Bad practice would have suggested to write POCO classes with a bunch of hard-coded data in it, and instantiate those classes wherever those data were needed. This would have lead to write comment\uncomment blocks of code, wherever I would have needed to switch from the data coming from the Web Service rather from the Mocked classes. It may work in the end, but I think we can do much better than this, don't we?

Moreover, one of the specifications was to ensure that the application would have worked even in a demo environment, rather than a live one. Bad practice would have suggested me to deploy two versions of the application, one pointing to the Web Service, and the other using the Mocked classes. This solution leaks from all sides, and sooner or later I would have drowned. Gluck!

What if my code would "depend on abstraction rather than concretions"? And what if I would be able to bind the real Service or the Mocked one only at RunTime? And what if it would not be me who cares about this?

That would be a dream.

Or probably, I would just need to learn how to Mock the Web Service using Moq, and how to Inject it using Ninject.

So say it once, say it loud: I'll do it and I'll be proud.

Background

This article explains how to use the Moq framework for Mocking a Service, and injecting the Mock class or the production version using a dependency injection design principle and Ninject as injector.

If you don't know what a dependency injection is, take 5 minutes of your time to read this.

If you want to learn how to setup Ninject in 120 seconds, take a look at this.

If you want to learn more about Moq and Ninject, feel free to visit these links:

Using the Code

Let's write a Client class responsible for log in a user into our application. The system must be able to automatically log in the user with his Windows Identity Credential, or, if not recognized, through a Username and a Password login form.

We are responsible to design the Front End, and we know that the Web Service will expose two methods:

  1. GET - getCurrentUser()
  2. POST - validateUser(string username, string password)

Both methods will return a UserDTO containing user details. The property IsAuthenticated needs to be used in order to check if the user has been authenticated by the server or not.

We want to be able to use either a ServiceMock class for testing or demo purposes, or a Service class with the implementation of the call to the WebService via Http.

In order to Inject either the ServiceMock or the Service class at runtime, we first code the Interface that needs to be implemented by both classes (N.B.: for a quick recall about Dependency Inject, check the links in Section 1.)

public interface IService {          

           UserDTO getCurrentUser();

           UserDTO postValidateUser(string userName, string passWord);
}

Easy peasy!

The real Service class would sound pretty much like this:

public class Service: IService {

 public UserDTO getCurrentUser() {
  // ... Target URL.
  string URL = "http://localhost/Accounts/CurrentUser";

  UserDTO currentUser = getUserUsingHTTPClient(URL).Result;
 
  return currentUser;  
 }

 public UserDTO postValidateUser(string userName, string passWord) {
  // ... Target URL
  string URL = "http://localhost/Accounts/ValidateUser";

  ValidateUserRequest vur = new ValidateUserRequest();
  vur.userName = userName;
  vur.passWord = passWord;

  UserDTO validatedUser = postUserUsingHTTPClient(URL, vur).Result;

  return validatedUser;  
 }
}

While the real fun is in Mockinq that class.

Let's first get MOQ from NuGet and have a look at GitHub.

public class ServiceMock : IService
    {
        Mock<IService> _service { get; set; }

        public ServiceMock()
        {
            _service = new Mock<IService>();

            // Setup getCurrentUser() case  
            _service.Setup(x => x.getCurrentUser()).Returns(getCurrentIdentity());

            // Setup postValidateUser(name, pwd) case
            // Password matches
            _service.Setup(x => x.postValidateUser(It.IsAny<string>(), 
            It.Is<string>(w => w.Equals("MoqAndNinject") )) ).Returns
            ((string userName, string password) => { return new UserDTO(userName, true); });

            // Password does not match
            _service.Setup(x => x.postValidateUser(It.IsAny<string>(), 
            It.Is<string>(w => !w.Equals("MoqAndNinject")))).Returns
            ((string userName, string password) => { return new UserDTO("DontTryToHackMe", false); });
        }

        public UserDTO getCurrentUser()
        {
            return _service.Object.getCurrentUser();
        }

        public UserDTO postValidateUser(string userName, string passWord)
        {
            return _service.Object.postValidateUser(userName, passWord);
        }

        private UserDTO getCurrentIdentity()
        {            
            return new UserDTO(WindowsIdentity.GetCurrent().Name, true);
        }        
    }
  • getCurrentUser() will return our Windows Identity Name
  • postValidateUser(string userName, string passWord) will authenticate you with whatever name you put, but if and only if you will enter the very secret password "MoqAndNinject"

Done.

Now we just need to Inject our ServiceMock into the View Model. It will take 60 seconds to do that, if you have already taken a look at the links in the first section.

Our Module will look like this:

public class DIModule : NinjectModule
 {
     public override void Load()
     {
         Bind<IService>().To<ServiceMock>(); // if using the Mock
         // Bind<IService>().To<Service>(); // if using the Service
     }
 }

Then, we would just use the injected class in our client:

public IService service { get; set; }

       public MainViewModel()
       {
           service = IocKernel.Get<IService>();
       }

Points of Interest

Once things are setup, it is so easy to customize your Mock Service, and use it for your Tests. I wanted to show how you can setup the MockObject to return an object from a method in your class (i.e.: getCurrentIdentity()) where you can implement your custom logic and return the object desired.

Or, if you are lazy like me, you just setup the Mock object by managing the possible scenarios (i.e.: in the postValidateUser case, those scenarios would have been only two:

  1. user enters the correct PWD
  2. user enters any other PWD

The point here is, how to Mock a class and inject it at runtime. So, I just gave a flavour of how the Service class would be implemented. There is no point in going into detail of how to use an HTTPClient to get a post a request to a Web Service.

How the Attached Example Works

It is a simple WPF project, coded using an MVVM approach.

At first, the window shows up recognizing you with your Windows Identity Name. The checkbok "IsAuthenticated" will be checked.

You can uncheck it, enabling the Ok Button which will try to authenticate you through the details you will enter into the UserName and Password text boxes. Remember to use the very secret password, if you want to be authenticated.

I would recommend to download it and take a look at the classes, since I have been adding some useful comments that may help you understand the whole story much better.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here