I read an article recently which said that mock objects are often misunderstood and misused. Are there any clear mocking anti-patterns which I can look out for?
-
is the article you read this one? martinfowler.com/articles/mocksArentStubs.html– kepplaCommented Jun 10, 2011 at 10:10
-
no... can't remember the exact source but will post here if I do– ArmandCommented Jun 13, 2011 at 11:12
-
I was taken to task on stackoverflow for mocking the mongodb API. I was pointed to a blog post that claimed it's wrong to mock any class you yourself did not write. I actually disagree with this but the opinion is out there.– KevinCommented Nov 7, 2011 at 1:35
5 Answers
I hate to see simple concrete classes mocked away. For example take the following simple class which has no dependencies on anything else:
public class Person
{
private readonly string _firstName;
private readonly string _surname;
public Person(string firstName, string surname)
{
if (String.IsNullOrEmpty(firstName))
{
throw new ArgumentException("Must have first name");
}
if (String.IsNullOrEmpty(surname))
{
throw new ArgumentException("Must have a surname");
}
_firstName = firstName;
_surname = surname;
}
public string Name
{
get
{
return _firstName + " " + _surname;
}
}
}
In any tests involving this class I'd much rather a real one was instantiated and used rather than some interface like 'IPerson' being pulled out, a mocked one used and expectations set on the . By using the real one your test is more realistic (you have the parameter checks in place and the real implementation of the 'Name' property). For a simple class like this you aren't making your tests slower, less deterministic or muddying the logic (you aren't likely to need to know that Name was called when testing some other class) - which are the usual reasons for mocking/stubbing.
As an extension to this I've also seen people write tests where the mock is set up with an expectation, then the mock is called directly in the test. Unsuprisingly the test will always pass...hmmmm...
-
Thankfully mocking frameworks that I've used have been able to mock concrete classes, so pulling out interfaces at inconvenient points is not an issue.– ArmandCommented Jun 13, 2011 at 11:13
-
5That doesn't change the issue - this sort of simple thing should generally not be mocked even if you're using something which relaxes technical constraints on what can be mocked (e.g. a mock framework like TypeMock or a dynamic language).– FinnNkCommented Jun 13, 2011 at 12:27
-
1My rule of thumb has always been to mock for behavior, not for data.– ardaveCommented Oct 15, 2013 at 17:41
It might sound obvious, but: Don't use mock objects in production code! I've seen more than one example where production code depended on the characteristics of certain mock objects (MockHttpServletRequest
from the Springframework for example).
-
14i hope you followed your holy duty and submitted the code to DailyWTF?– kepplaCommented Jun 10, 2011 at 10:17
-
1In my previous work we were expressly forbidden from submitting anything from our codebase to DWTF. Commented Jun 10, 2011 at 15:25
-
9@quant_dev: The fact that they had such a policy implies scary things about their developers... Commented Jun 10, 2011 at 17:31
-
1Not really. It was a startup which had to develop a codebase quickly to sell a product, and then started consolidating and refactoring it to pay off the technical debt, as the product matured and further development was hindered by the (lack of) initial design. Managers knew the old codebase was shit, and invested time and resources into refactoring, but didn't want to risk any adverse publicity. Commented Jun 11, 2011 at 11:03
-
Just taking shortcuts isn't really enough to get you only dailywtf...– poolieCommented Sep 12, 2012 at 7:18
In my opinion it's the excessive method invocation check on mocks. I feel that this is a practice enforced by a few mocking frameworks like EasyMock, where the default mock behavior is to fail whenever there is an additional method invocation that what wasn't exactly specified before. This kind of strict mock method checking can lead to brittle designs where the tiniest change to the code can lead to a whole suite of tests failing, even though the core functionality is still the same.
A solution to this is starting to use stubs instead of mocks. An article I've found particularly enlightening about the subject was one found in Mockito's Javadoc: http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html (see "2. How about some stubbing?"), linking to: http://monkeyisland.pl/2008/07/12/should-i-worry-about-the-unexpected/.
I've enjoyed working with Mockito so far because it does not enforce this strict mocking behavior but the use of stubs instead. It also enforces method checking on specific ones instead of the whole mock object; so you end up checking only methods that really matter in your test scenario.
There are a few books here and there I can recommend that touch this subject and mocking and general:
xUnit Patterns
The Art of Unit Testing: With Examples in .Net
Next Generation Java Testing: TestNG and Advanced Concepts (this book is mostly about testNG but there's a nice chapter about mocking)
-
+1 for the point on excessive method invocation checks. However, there is always the flip side of the coin where an unexpected method invocation causes a failure in your method. Thankfully Mockito has the
Answer.RETURNS_SMART_NULLS
setting for mocks which helps diagnose this. Commented Nov 7, 2011 at 2:15
I have observed few anti-patterns in my experience.
- Domain classes being mocked/stubbed where a state change may occur and that needs to be verified.
- Integration tests interacting with a mix of mocks and concrete classes which defeats the purpose of integration tests.
- Inadvertent use of mocks in production code (This should never happen)
Otherwise my experience with mocks especially Mockito has been a breeze. They have made tests very easy to write and maintain. GWT view/presenter interaction testing is much more easy with mocks than the GWTTestCase.
-
2 & 3 are definite problems! Have you got a simple example of (1)?– ArmandCommented Jun 13, 2011 at 11:15
I find that tests which utilise mocks across multiple layers of an application particularly difficult to decipher and change. However I think this has been mitigated in recent years by improved mock framework API's (I use JMock where convenient).
5 or 6 years ago API's like EasyMock were powerful but very cumbersome. Often the test code that made use of it was orders of magnitude more complicated than code it was testing. Back then I tried to influence teams I was in to use it very sparingly and make do with simple handcrafted mocks that were simply alternate implementations of interfaces specifically for testing.
Recently my strong opinions on this have become softer as the mocking API's have made tests that utilise them more readable. Essentially I want my code (including tests) to be changeable by other developers without making them feel like they're sifting through a mire of obscure API calls.