Wednesday, 15 April 2009 09:00 by
hadi
Having a chat with a colleague the other, brought up the issue of strict mocks. I commented that strict mocks should be used sparingly and only in certain circumstance, and this led to a series of discussions on why that is.
Strict and loose Mocks
Usually mocking frameworks provide two types of mocks: strict and loose. If you're using RhinoMocks, these are called StrictMock and DynamicMock. If you're using Moq, you set the behaviour (Loose = Dynamic = Default or Strict) in the mock creation.
RhinoMocks
RhinoMock has a static mock repository that you can use to create mocks, called MockRepository. This saves you on having to explicitly create a mock repository. Thus, instead of doing:
1: MockRepository mocks = new MockRepository();
2:
3: IDependency dependency = mocks.DynamicMock<IDependency>();
you could write this:
1: IDependency dependency = MockRepository.GenerateMock<IDependency>();
Using the static repository, you cannot pick between dynamic and strict mocks. All mocks are dynamic. This somehow promotes the usage of dynamic mocks over strict ones.
Moq
With Moq, as with RhinoMocks, the default behaviour is of loose mocks. Thus, writing:
1: var dependency = new Mock<IDependency>();
is equivalent to:
1: var dependency = new Mock<IDependency>(MockBehavior.Loose);
which in turn is the same as:
1: var dependency = new Mock<IDependency>(MockBehavior.Default);
If you want to use strict mocks:
1: var dependency = new Mock<IDependency>(MockBehavior.Strict);
(Note that with Moq, to access the actual Mocked object, you need to access the .Object property. RhinoMocks doesn't require this because it uses extension methods).
Using Strict Mocks
So, now that we know how to create the two different types of mocks depending on the framework, let's take a look at a SUT and see where the problem with strict mocks lie. To make the post shorter, I'll use RhinoMocks, but you can accomplish the same with Moq.
Suppose we have the following class:
1: public class ServiceClass
2: { 3: private readonly IDependency _dependency;
4:
5: public ServiceClass(IDependency dependency)
6: { 7: _dependency = dependency;
8: }
9:
10: public void FirstMethod()
11: { 12: _dependency.FirstMethod();
13: Console.WriteLine("Called ServiceClass.FirstMethod"); 14: }
15:
16: public void SecondMethod()
17: { 18: _dependency.SecondMethod();
19: Console.WriteLine("Called ServiceClass.SecondMethod"); 20: }
21: }
and we want to test that when calling ServiceClass.FirstMethod, the corresponding call Dependency.FirstMethod is called, we could be tempted to do something like the following:
1: [Fact]
2: public void ServiceClass_FirstMethod_calls_dependency_FirstMethod_Strict()
3: { 4: MockRepository mocks = new MockRepository();
5:
6: IDependency dependency = mocks.StrictMock<IDependency>();
7:
8: using (mocks.Record())
9: { 10: dependency.Expect(m => m.FirstMethod());
11: }
12:
13: using (mocks.Playback())
14: { 15: ServiceClass serviceClass = new ServiceClass(dependency);
16:
17: serviceClass.FirstMethod();
18: }
19:
20: // Note that in the Record/Replay, VerifyAll is implicitly called
21: }
We've verified that Dependency.FirstMethod is called, everything passes, all is fine.
Welcome to BrittleVille
Two days later we get a change of request, that requires us to adjust the code for ServiceClass.FirstMethod. In particular, we need to call Dependency.ThirdMethod:
1: public void FirstMethod()
2: { 3: _dependency.FirstMethod();
4: _dependency.ThirdMethod();
5: Console.WriteLine("Called ServiceClass.FirstMethod"); 6: }
We check in the changes, run our tests, and boom! Test failed:
XunitException: Rhino.Mocks.Exceptions.ExpectationViolationException : IDependency.ThirdMethod(); Expected #0, Actual #1.
With strict mocks EVERY single call to the mocked object has to have expectations set on it. If we make an additional call and we don't set the expectation, our test will fail. Our test was to verify the FirstMethod was being called, and it still is. Our test failed because we wrote it using strict mocks, it failed for the wrong reason, and made our code very brittle.
However, if we were to have written the test using Dynamic mocks, this wouldn't happen:
1: [Fact]
2: public void ServiceClass_FirstMethod_calls_dependency_FirstMethod_Dynamic()
3: { 4: MockRepository mocks = new MockRepository();
5:
6: IDependency dependency = mocks.DynamicMock<IDependency>();
7:
8: using (mocks.Record())
9: { 10: dependency.Expect(m => m.FirstMethod());
11: }
12:
13: using (mocks.Playback())
14: { 15: ServiceClass serviceClass = new ServiceClass(dependency);
16:
17: serviceClass.FirstMethod();
18: }
19:
20: // Note that in the Record/Replay, VerifyAll is implicitly called
21: }
Note that out test is still valid. If we remove the call to Dependency.FirstMethod the test will fail as it should. However, it won't fail if we add additional calls.
An added bonus to using loose mocks with RhinoMocks, is that you can use the AAA (Arrange-Act-Assert) syntax and also call individual expectations. Thus the previous code could be written like so:
1: [Fact]
2: public void ServiceClass_FirstMethod_calls_dependency_FirstMethod_AAA() { 3:
4: // Arrange
5: IDependency dependency = MockRepository.GenerateMock<IDependency>();
6:
7: dependency.Expect(m => m.FirstMethod());
8:
9:
10: // Act
11: ServiceClass serviceClass = new ServiceClass(dependency);
12:
13: serviceClass.FirstMethod();
14:
15: // Assert
16: dependency.VerifyAllExpectations();
17:
18: }
Alternatively, if you don't need expectations to return values, you can just call AssertWasCalled on them:
1: [Fact]
2: public void ServiceClass_FirstMethod_calls_dependency_FirstMethod_AAA() { 3:
4: // Arrange
5: IDependency dependency = MockRepository.GenerateMock<IDependency>();
6:
7: // Act
8: ServiceClass serviceClass = new ServiceClass(dependency);
9:
10: serviceClass.FirstMethod();
11:
12: // Assert
13: dependency.AssertWasCalled( m => m.FirstMethod());
14:
15: }
Summary
Mocks are a great thing to test behaviour between different components. However, make sure you use them correctly if you don't want to end up with brittle code that any minor change breaks a whole bunch of tests. Strict and ordered mocking should only be used in exceptional cases.
Tuesday, 31 March 2009 08:54 by
hadi
A question popped up today about someone having trouble mocking the UserAgent property of a Controller. There's enough information on the Internet with solutions to this problem, so I'm going to describe how to figure it out if you don't have an Internet connection.
Let's assume we need to test that our Index action in our HomeController displays the UserAgent information:
1: public ActionResult Index()
2: { 3: // Don't use ViewData at home kids! This is just a demo
4: ViewData["UserAgent"] = Request.UserAgent;
5:
6: return View();
7: }
Our test would look something like:
1: [TestMethod]
2: public void Index()
3: { 4:
5: HomeController controller = new HomeController();
6:
7: ViewResult result = controller.Index() as ViewResult;
8:
9: ViewDataDictionary viewData = result.ViewData;
10: Assert.AreEqual("Mozilla/5.0 ....", viewData["UserAgent"]); 11: }
If we run this, it will fail with an exception, reason being that Request is null in our test. This makes sense because we're not coming in from a browser, we're just calling a method on a class. Therefore, what we need to do is somehow inject a fake Request in there with some value assigned to the UserAgent. The problem is how....
Reflector is your friend
Now, ASP.NET MVC comes with source code that you can download from Codeplex. Having the source code makes it easy to figure out how things work. But we're assuming that you don't have an Internet connection remember? And you forgot to download the source code. So let's fire up Reflector and see what it shows us.
We open up Reflector and load System.Web.Mvc, and locate the Controller class. Since we're trying to access the Request property of the Controller, that's the first thing we want to look up:
Hmm, it looks like the Request property is really coming from the HttpContext property. Clicking on that gives us:
We see that the HttpContext is being obtained from the ControllerContext. So let's continue to drill down to ControllerContext:
Aha! Looks like we've reached the end. ControllerContext is a read-write property. This means that if we provide a fake ControllerContext in our test, one that contains a fake HttpContext which in turn contains a fake Request with our UserAgent, we're all set.
Working our way backwards
I'm going to use Moq as my mocking framework, but you can use any other framework, such as RhinoMocks. Instead of trying to declare a whole bunch of mocks first, in a true TDD fashion let's work our way backwards. First thing we need is a mock ControllerContext. In Moq, the actual mocked object is accessed via the Object property (I'm using screenshots so you can better contemplate the process):
As we can see, we've added a controllerContext mock object and so the next step is to create this object:
Now, our controllerContext needs the HttpContext property set:
The lines boxed in red are what we've added new. Now that we have our mocked ControllerContext and our HttpContext, the only thing left is to setup the UserAgent property of our Request. But to do that, we need another mock, the HttpRequest object:
We therefore create the new mock object and setup the UserAgent property:
Our complete test now looks like this:
And running it should give us a successful pass!
Refactoring
Now that we've understood exactly what's required, let's see if we can clean up the test a bit:
See what's happened? We've removed the mock objects for both the HttpRequest and the HttpContext. The reason we can do this is because of how Moq works, creating proxies for reference types. Therefore, HttpContext is actually not null, and nor is Request even though we haven't specifically created a mock for them. This allows us to easily access the UserAgent property and set it to the value required. Saves quite a bit of code
Summary
Mocking can sometimes seem complicated, not knowing what you're meant to do to get something to work. But all you need to do is take a step back, analyze what is it you're trying to mock and work your way up. Having tools like Reflector make this easier!
Friday, 12 September 2008 21:21 by
Hadi
In a follow-up to my previous post on mocking, here is the same code re-factored so that it does not depend on the internal behavior of GetAllEmployeesByCompanyId
1: [TestMethod]
2: public void GetAllEmployeesByCompanyId_When_Employees_Are_Marked_Returns_Non_Marked_Employees()
3: { 4: IEmployeeRepository employeeRepository = MockRepository.GenerateMock<IEmployeeRepository>();
5:
6: User user = new User { Id = Guid.NewGuid()}; 7:
8: Employee employee = new Employee {Id = Guid.NewGuid()}; 9:
10: Employee deletedEmployee = new Employee { Id = Guid.NewGuid(), DeletedBy = user}; 11:
12: employeeRepository.Stub(x => x.GetEmployeesByCompanyId<Employee>(Guid.Empty)).Return(new List<Employee>
13: { 14: employee,
15: deletedEmployee
16: });
17:
18: var EmployeeServices = new EmployeeServices(employeeRepository);
19:
20: var employees = EmployeeServices.GetAllEmployeesByCompanyId(Guid.Empty);
21:
22: Assert.AreEqual(1, employees.Count);
23: }
I've done quite a bit of re-factoring, taking advantage of some of the C# 3.0 language features. I'm also using RhinoMocks 3.5 which also makes use of extension methods. In general the test is much cleaner, less noise. In fact, apart from two "strange" calls (lines 4 and 12), you wouldn't even notice it's using mocks.
The important change is that its no longer brittle. If you recall correctly, from my previous post, the purpose of the test was to validate that when GetAllEmployeesByCompanyId, only records not marked for deletion were returned. It was not about interaction or the internal behavior of the call. As such, we've removed this tight coupling to the actual implementation by
a) Replacing the strict mock with a dynamic mock [Line 4].
In version 3.5 of RhinoMocks, you no longer need to create a mock repository if you don't want to. As such, you have static methods on the MockRepository class that generate mocks for you. By default, the mock generated is Dynamic. Therefore, the call MockRepository.GenerateMock is a dynamic mock.
b) Removing the call to VerifyAll.
Since we do not set any expectations, we do not really need or want to verify that any specific calls were made. Again, that's not the purpose of this particular test.
In line 12, we've stubbed the call to GetEmployeesByCompanyId of EmployeeRepository so that it returns a list with two employees. If the repository call were to not return a value, we wouldn't even need to explicitly stub it.
As you can see, we are still using mocks, yet we are not making our test volatile to change. We are using mocks to mock out non existent functionality. This doesn't mean to say that we shouldn't use mocks for verifying behavior. But we should only do that if the purpose of the test is that. In this case it isn't.
RhinoMocks 3.5 is pretty cool. It allows a lot of the noise surrounding mocking to be eliminated in tests. Hopefully I'll blog more about it as I use this version more, but be sure to check it out (Don't be lazy...Just Google it!)
Friday, 12 September 2008 06:56 by
hadi
Take a look at the following test:
1: public void EmployeeServicesTest_GetAllEmployeesByCompanyId_When_Employees_Are_Marked_Returns_Non_Marked_Employees()
2: {
3: var guid = Guid.NewGuid();
4: var guid2 = Guid.NewGuid();
5: var guidComp= Guid.NewGuid();
6:
7: MockRepository mocks = new MockRepository();
8:
9: IEmployeeRepository mockRepository = (IEmployeeRepository)mocks.StrictMock(typeof(IEmployeeRepository));
10:
11:
12: User user = new User();
13: user.Id = Guid.NewGuid();
14:
15: Employee deletedEmployee = new Employee();
16: deletedEmployee.Id = guid;
17: deletedEmployee.DeletedBy = user;
18:
19: Employee validEmployee = new Employee();
20: validEmployee.Id = guid;
21:
22: Expect.Call(mockRepository.GetEmployeesByCompanyId<Employee>(guidComp)).Return(new List<Employee>() { deletedEmployee, validEmployee });
23:
24: mocks.ReplayAll();
25:
26: var EmployeeServices = new EmployeeServices(mockRepository);
27:
28: var testList = EmployeeServices.GetAllEmployeesByCompanyId(guidComp);
29:
30: Assert.AreEqual(1, testList.Count);
31:
32: mocks.VerifyAll();
33: }
I won't get into the naming conventions since I've covered those in previous blog entries. This test has another problem. It's trying to validate that when you ask for a list of employees, only those that are not marked as deleted are returned. To simulate the data returned, it is making use of a mock repository (RhinoMocks).
Before looking at the issue, let's decide what the purpose of the test is. We want to test that when a system has two employees, one of whom is marked for deletion, a call to GetAllEmployeeesByCompanyId returns only one employee. Therefore the SUT is that method call.
In line 9, a mock of the repository is created, of type StrictMock. This is a particular call of RhinoMocks, but pretty much all mocking frameworks have the same feature. A strict mock indicates that every expected call should be made. Therefore, when on line 32 a call to VerifyAll is made, this test will fail if mockRepository.GetEmployeesByCompanyId has not been called with those exact arguments. In our case, the test passes and all is fine. Or is it?
The problem however if we change the internal functionality of EmployeeServices.GetAllEmployeesByCompanyId. If some reason or other we make a second call to EmployeeRepository, that doesn't change the outcome of the method, this test will fail.
Why is that? The reason isn't so much that we are using StrictMock as opposed to DynamicMock. The problem is that we are trying to test too many things in the same test. In actual fact, in this particular case, only ONE thing should be tested: retrieving one employee out of two. However the introduction of a StrictMock and the VerifyAll call has had the side-effect of introducing an interaction test, something we are not interested in.
Mocks can be great and very powerful. But use them wisely. If you start creating strict mocks (which should only be used for interaction/behavioural testing), then you're just making your tests very brittle. The slightest change in behaviour, even though it's encapsulated inside the method being tested can break your test. This pretty much defeats the whole advantage of unit tests. We create tests to isolate functionality and test that functionality in isolation. As soon as we tightly couple our tests to a particular implementation, and when the system under test is not trying to validate that implementation, the whole thing blows up. In another blog post, I'll re-factor the test to make it much simpler and less volatile.