If you are new to the idea of mocking, then think of it as a way to simulate (or "mock") the behaviour of an object, where you can control exactly how you want the mocked object to behave. The mocked object can simulate a class that you have written from scratch or it can even simulate a class that you don't have the source code for (e.g. a BCL class).
A good example of when you would want to mock an object is when you are writing a unit test. Let's imagine that your unit test is exercising a method called RegisterUser on your UserService class. The UserService class constructor accepts an interface called IEmailService as one of its parameters. The IEmailService defines one method called SendRegSuccessEmail (which returns a boolean that indicates whether the email was fired off successfully). The RegisterUser method accepts two parameters, an email and a password and returns a boolean that indicates if registration was successful. The implementation of this method checks if the supplied email already exists, if it doesn't, then it saves the email and password in some repository, sends an e-mail to the user telling them that their registration was successful and returns true. If registration fails (e.g. if the user already exists in the repository) then false is returned.
With this setup, imagine that you now wanted to write a unit test that tests whether the RegisterUser method prevents multiple registrations for a single email. As the developer of the RegisterUser method, you know that it uses the IEmailService to fire off an e-mail - and that you (obviously) don't want to fire off e-mails in your unit test. This is where mocking comes into play. You can setup your test so that you mock an implementation of the IEmailService interface and control how you want the SendEmail method to behave. Using the Moq library, your setup would look like:
var emailServiceMock = new Mock<IEmailService>();
emailServiceMock
.Setup(es => es.SendRegSuccessEmail(It.IsAny<string>()))
.Returns(true);
var userService = new UserService(emailServiceMock.Object, ...);
// Test userService.RegisterUser(...)
You can now write the remaining bit of your unit test using the userService object with the knowledge that you'll never fire off unnecessary e-mails when calls are made to the IEmailService.SendEmail method. As can be seen in the snippet above, it is quite simple to setup a mock, you instantiate an instance of the generic Mock class and pass in the object-to-mock as a type parameter (in this case IEmailService). The next line tells the mock object that whenever the SendRegSuccessEmail method is called with any string parameter (It.IsAny<string>()), then return the boolean value true. You can try this for yourself and you'll find that the following expression will always equal true:
emailServiceMock
.Setup(es => es.SendRegSuccessEmail(It.IsAny<string>()))
.Returns(true);
var userService = new UserService(emailServiceMock.Object, ...);
// Test userService.RegisterUser(...)
emailServiceMock.Object.SendRegSuccessEmail("foo@bar.com")
Once the mock object is setup, you can get the actual mocked object instance using the "Object" property on the Mock class - the returned instance from this property can then be used in any location that it is expected (in the snippet, we've passed the mocked instance into the UserService constructor). The RegisterUser method will therefore use this mock and we'll avoid the unwanted scenario of emails getting fired off whenever our unit tests are executed!
No comments:
Post a Comment