In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways. A computer programmer typically creates a mock object to test the behavior of some other objectWhen you write a unit test, you want to try and focus on testing a single class. But, in any complex system, classes use other classes. So, in that situation, how do you just test one class? You separate class creation from class usage: The class you're trying to test never contains the "new" keyword. Instead, it receives the classes it depends on through it's constructor or setters (the formal term for this is Dependency Injection). So your code that used to look like this:
public void useDependency() {
new Dependency().useDependency();
}
Now looks like this:public void setDependency(Dependency dependency) {Yes, there's a little bit more code, but now it's easy to test.
this.dependency = dependency;
}
public void useDependency() {
this.dependency.useDependency();
}
In Michael Feather's book, Working Effectively With Legacy Code, he describes the difference between a Mock and a Fake object. A mock object verifies its own state is correct. A fake object, on the other hand, has its state tested by an external object (typically the testcase it's created in).
Before I discovered Mockito, I got by with Fake objects. Fake objects have some problems though. The main problem is you have to make them yourself. If you need a fake interface, but you're only testing one method, you still have to manually stub out all the other methods.
For example, I'm making a Swing app and when I wrote test cases for my client, I had to make a fake Graphics object. With just stub methods, this class is about 300 lines!
So then I tried JMockit, but I had some major complaints. It's tutorial is horrid and scattered all over the place. Whenever I tried to use it, I always had to open its documentation after realizing I wasn't using it correctly. What makes this worse is it's not easy to discover you're using it incorrectly! If you do something wrong, it'll usually return null instead of throwing an exception. 99% of the time, you pass this null pointer into a setter and you eventually get a NullPointerException in the middle of your test. Why doesn't it fail immediately? Also, it seems like you have to use different API calls for mocking concrete classes vs interfaces (or maybe it doesn't work with concrete classes. Here's a fun exercise: See if you can figure that out on your own. See what I mean by the horrid documentation?). Plus, you need special VM arg to run it.
JMockit has one redeeming quality (that's actually very cool): It lets you inject classes even if you're not using dependency injection. At first that may not seem possible, but check out its "documentation" to see how. For this reason, I would still use this library if I was trying to test crappy legacy code that I was terrified to change in any way.
Next, I looked at EasyMock for about 3 minutes. I couldn't figure it out with that amount of time so I moved on (I know, not a fair review, but at least an honest one).
Then, by luck, I stumbled upon this controversial, unrelated article and in a comment I saw a reference to Mockito. I checked it out and it turns out to be the best of all worlds. It saves you from writing fakes, it's documentation/API is concise, consistent and without ambiguity, it doesn't require extra VM arguments, and, you can learn it in under 3 minutes.
I highly recommend it to anyone who's writing unit tests. It saves me a lot of time while simultaneously making my code more readable.
BTW, if you're already using EasyMock, here's a Mockito article on Mockito VS EasyMock.
