Today, Bob Martin tweeted :
I use mocking frameworks as little as possible. I think heavy reliance on a mocking framework is a smell. I usually write my own mocks.
|
I agree with this. Of course the 140 characters allowed in a tweet don’t really give much space to explain what that smell is. So let’s refine our nose.
Mocks let you test implementation. Anyone who ever gets uppity about the use of stubs, fakes & mocks is paying a lot of attention to this. With a mock you can verify that something has been called. While this can be useful, it is rarely part of the Behavior of a system, and often part of the implementation. Since there are literally 1,000’s of way to program the exact same behavior, Unit tests that lock a particular implementation will actually in up “protecting” your code from being refactored. This smell tends to come up in newly written code, and is usually accompanied by the phrase
“anytime I want to change anything a bunch of tests break and I have to go and fix them”.
Mocks let you fake very hard to fake calls. Ever need to mock out a call to HttpServletRequest? There are over 40 methods on that interface. Even with the help of your IDE, that’s a pain. A good mocking framework (I prefer EasyMock) will let you do it in 2-3 lines. This is great, especially in legacy code, or API’s you don’t control. But it’s a cover for a much more insidious smell that exists in HttpServletRequest. Simply put, an interface should not have 40 methods. Now you might argue that was how many were needed to handle something as complex as a web call. And you would be wrong. Take a look at Rack (or our Port of it - JRack) it handles everything with 1 simple abstraction.
When mocks are the easiest way to gain an handle into your code, you have coupled you code too tightly, and not left enough inserts points.
Mocks let you fake calls. Lastly, mocks let you fake easy calls too. One example I use a lot is Loaders. My Loader interface looks like this:
public interface Loader<T> { public T load() throws Exception; } |
I will constantly be making calls like
request.init2Edit(new MockLoader<Member>(member));
|
But here a mocking framework is overkill. It’s so easy to write the above line, than
Loader<Member> loader = EasyMock.createMock(Loader.class); EasyMock.expect(loader.load()).andReturn(member); request.init2Edit(loader);
|
If I’ve kept my code clean, mocking frameworks just aren’t that useful.
So hopefully you will start to sense the same things in your code. Of course if your nose is prickling over some hard to test piece of code, grab your mocking framework. It’s your first line of attack. Like grabbing some cologne when you are a bit smelly and guest are coming over, just realize that eventually you have to take a bath.
2 comments:
I prefer the EasyMock version because the mock behavior is very clear and cohesive with the test.
Your example doesn't show the implementation of MockLoader which I presume you have to write yourself. Also this mock implementation is somewhere else and not as clearly associated with this test.
We make heavy use of Rhino Mocks in our code base, and yes we have many parts where the code reeks from overuse of expectations, however with RhinoMocks 3.5 we can easily use dynamic mocks to focus our tests on specific functionality.
I have found people using mocks to mock an interface when use of their concrete objects would have been just as simple to use. If you don't need to hide cascading dependencies, for example DTOs or other classes with no dependencies, there is no reason not to use your actual implementation.
I have posted in the past about mock tests that prevent you from refactoring a line of code without breaking the test. I call these AssertNobodyTouchesMyCode() tests. These are really, really, bad and should be avoided at all costs.
Post a Comment