In the last part of my Dependency Injection article I introduced the term of “mocking”. This kind of test double can be really powerful. Yet in my example I had to create 2 new classes (my mocks) to be able to test my functionality in order to reduced coupling. Here is the code used by the tests:
class MockNotifier : INotifier { public MockNotifier() { NotifyHasBeenCalled = false; } public bool NotifyHasBeenCalled { get; private set; } public void Notify(User user) { NotifyHasBeenCalled = true; } } class MockRepository : IUserRepository { public bool HasValidatedNotification { get; set; } public User GetById(int userId) { return new User { HasActivatedNotification = HasValidatedNotification }; } } [TestClass] public class NotificationServiceTest { private NotificationService _notificationService; private MockNotifier _mockNotifier; private MockRepository _mockRepository; [TestInitialize] public void TestInit() { _mockNotifier = new MockNotifier(); _mockRepository = new MockRepository(); _notificationService = new NotificationService(_mockRepository, _mockNotifier); } [TestMethod] public void NotificationActivated() { _mockRepository.HasValidatedNotification = true; _notificationService.NotifyUser(1); Check.That(_mockNotifier.NotifyHasBeenCalled).IsTrue(); } [TestMethod] public void NotificationDeactivated() { _mockRepository.HasValidatedNotification = false; _notificationService.NotifyUser(1); Check.That(_mockNotifier.NotifyHasBeenCalled).IsFalse(); } }
I think that being able to write its own mocks is a great exercise to understand Oriented Object Programming (OOP) in a testing context. But in a larger application it is likely that you will have an enormous amount of them, it is a lot of code to maintain. This is why I will introduce a mocking framework name Moq.
I used this nuget package for a few months now and it offers a lot of helpful functionalities. But I think that it can be a bit complex to use at first when people are not familiar with the mocking technique. Let’s see how the previous code can be refactored when using Moq:
[TestClass] public class NotificationServiceTest { private NotificationService _notificationService; private Mock<INotifier> _mockNotifier; private Mock<IUserRepository> _mockRepository; private User _fakeUser; [TestInitialize] public void TestInit() { _mockNotifier = new Mock<INotifier>(); _mockRepository = new Mock<IUserRepository>(); _notificationService = new NotificationService(_mockRepository.Object, _mockNotifier.Object); _fakeUser = new User(); _mockRepository.Setup(m => m.GetById(It.IsAny<int>())).Returns(_fakeUser); } [TestMethod] public void NotificationActivated() { _fakeUser.HasActivatedNotification = true; _notificationService.NotifyUser(It.IsAny<int>()); _mockNotifier.Verify(m => m.Notify(It.IsAny<User>()), Times.Once()); } [TestMethod] public void NotificationDeactivated() { _fakeUser.HasActivatedNotification = false; _notificationService.NotifyUser(It.IsAny<int>()); _mockNotifier.Verify(m => m.Notify(It.IsAny<User>()), Times.Never()); } }
First thing to be aware of is that the manipulated object are Mock instances and not implementations of the interfaces. It is possible to access these implementations by using the Object property of the Mock to inject the dependencies to a client object (NotificationService in this case). I also used the Setup method of the MockRepository to return a new instance of User when the GetById method is called.
Moq also provides a Verify method to check whether or not a method has been called and how many times. This is the method I used in the test to validate my test scenarios. You can notice that I no longer used NFluent, because in this case I don’t need it. Yet it is possible to use NFluent with Moq for the tests, they work really well together.
Last but not least, Moq provides powerful methods to match arguments, in my example it is the It.IsAny method. With this I can tell my Mock to accept any value as parameter because I am not testing it in my unit tests since it is irrelevant in this testing context.
This is just a quick overview of the possibilities offered by Moq and I encouraged you to check this awesome mocking framework.
See you next time !
Reblogged this on public interface IReadable { }.
LikeLike