Understanding Mock and frameworks - Part 4 of N
I am glad that this series has been liked by large audience and even got focus on Channel9 Video and that motivates to continue this series further on.
This series on Mock and frameworks takes you through Rhino Mocks, Moq and NSubstitute frameworks to implement mock and unit testing in your application. This series of posts is full of examples, code and illustrations to make it easier to follow. If you have not followed this series through, I would recommend you to read following articles
- Understanding Mock and frameworks – Part 1 of N – Understanding the need of TDD, Mock and getting your application Unit Test ready
- Understanding Mock and frameworks – Part 2 of N – Understanding Mock Stages & Frameworks – Rhino Mocks, NSubstitute and Moq
- Understanding Mock and frameworks – Part 3 of N - Understanding how to Mock Methods calls and their Output – Rhino Mocks, NSubstitute and Moq
This part of the series will focus on exception management, and subscribing to events
Exception Management
Going back to the second post where we defined our Controller and Service interface, the method GetObject throws an ArgumentNullException when a NULL value is passed to it. The Exception Management with Mock allows you to change the exception type and hence, ignore the exception peacefully.
Using Rhino Mocks
Using the Stub method of Mocked Service, you can override the exception type. So instead of getting a ArgumentNullException, we will change the exception to InvalidDataException. But do not forget to add a ExceptedException attribute to the method (line 2 in example below) that ensures a peaceful exit.
- [TestMethod]
- [ExpectedException(typeof(InvalidDataException))]
- public void T05_TestExceptions()
- {
- var service = MockRepository.GenerateMock<IService>();
- // we are expecting that service will throw NULL exception, when null is passed
- service.Stub(x => x.GetObject(null)).Throw(new InvalidDataException());
- Assert.IsNull(service.GetObject(null)); // throws an exception
- }
Using NSubstitute
NSubstitute does not expose a separate /special function like Throw. It treats exceptions as a return value of the test method. So u
- [TestMethod]
- [ExpectedException(typeof(InvalidDataException))]
- public void T05_TestExceptions()
- {
- var service = Substitute.For<IService>();
- // we are expecting that service will throw NULL exception, when null is passed
- service.GetObject(null).Returns(args => { throw new InvalidDataException(); });
- Assert.IsNull(service.GetObject(null)); // throws an exception
- }
Using Moq
Moq exposes Throws method just like Rhino Mocks
- [TestMethod]
- [ExpectedException(typeof(InvalidDataException))]
- public void T05_TestExceptions()
- {
- var service = new Mock<IService>();
- // we are expecting that service will throw NULL exception, when null is passed
- service.Setup(x => x.GetObject(null)).Throws(new InvalidDataException());
- Assert.IsNull(service.Object.GetObject(null)); // throws an exception
- }
Event Subscriptions
The next topic of interest in this series is managing Event Subscriptions with Mock frameworks. So the target here is to check if an event was called when some methods were called on the mocked object
Using Rhino Mocks
The code here is little complex compared to all previous examples. So we are adding a ServiceObject to the controller which raises an event. Unlike real time examples, this event is hooked to the DataChanged method of the service. This means the controller will raise an event and a service method will be called dynamically.
- [TestMethod]
- public void T06_TestSubscribingEvents()
- {
- var service = MockRepository.GenerateMock<IService>();
- var controller = new Controller(service);
- controller.CEvent += service.DataChanged;
- ServiceObject input =new ServiceObject("n1", Guid.NewGuid());
- controller.Add(input);
- service.AssertWasCalled(x => x.DataChanged(Arg<Controller>.Is.Equal(controller),
- Arg<ChangedEventArgs>.Matches(m=> m.Action == Action.Add &&
- m.Data == input)));
- }
Let’s go into detail of the AssertWasCalled statement – it takes a method handler in the lambda expression. Some of the other methods of interest are Arg<T> Is.Equal and Matches. The method Arg<T> creates a fake argument object of a particular type. Is.Equal() method assigns a value to it and Matches method adds like a filter on the values of input parameters to the original ‘DataChanged’ method.
Using NSubstitute
NSubstitute has a different set of methods for event subscription. The output of Received() method exposes all valid method calls available, Arg.Is<T>() creates fake object for mocked service.
- [TestMethod]
- public void T06_TestSubscribingEvents()
- {
- var service = Substitute.For<IService>();
- var controller = new Controller(service);
- controller.CEvent += service.DataChanged;
- ServiceObject input = new ServiceObject("n1", Guid.NewGuid());
- controller.Add(input);
- service.Received().DataChanged(controller,
- Arg.Is<ChangedEventArgs>(m => m.Action == Action.Add && m.Data == input));
- }
Using Moq
Apart from having different names of methods from NSubstitute, Moq does exactly the same as other two frameworks
- public void T06_TestSubscribingEvents()
- {
- var service = new Mock<IService>();
- var controller = new Controller(service.Object);
- controller.CEvent += service.Object.DataChanged;
- ServiceObject input = new ServiceObject("n1", Guid.NewGuid());
- controller.Add(input);
- service.Verify(x => x.DataChanged(controller,
- It.Is<ChangedEventArgs>(m => m.Action == Action.Add && m.Data == input)));
- }
The Code for Download
Understanding RhinoMocks, NSubstitute, Moq by Puneet Ghanshani
So that concludes how to use Rhino Mocks, NSubstitute and Moq for Exception Handling and Event Subscriptions. Should you have any questions, feel free to comment on this post.