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:
GET
- getCurrentUser()
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() {
string URL = "http://localhost/Accounts/CurrentUser";
UserDTO currentUser = getUserUsingHTTPClient(URL).Result;
return currentUser;
}
public UserDTO postValidateUser(string userName, string passWord) {
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>();
_service.Setup(x => x.getCurrentUser()).Returns(getCurrentIdentity());
_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); });
_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>(); }
}
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:
- user enters the correct PWD
- 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.