13

This is what I found from my initial attempts to use JMockIt. I must admit that I found the JMockIt documentation very terse for what it provides and hence I might have missed something. Nonetheless, this is what I understood:

Mockito: List a = mock(ArrayList.class) does not stub out all methods
of List.class by default. a.add("foo") is going to do the usual thing
of adding the element to the list.

JMockIt: @Mocked ArrayList<String> a;
It stubs out all the methods of a by default. So, now a.add("foo")
is not going to work.

This seems like a very big limitation to me in JMockIt.
How do I express the fact that I only want you to give me statistics
of add() method and not replace the function implementation itself
What if I just want JMockIt to count the number of times method  add()
was called, but leave the implementation of add() as is?

I a unable to express this in JMockIt. However, it seems I can do this
in Mockito using spy()

I really want to be proven wrong here. JMockit claims that it can do everything that other mocking frameworks do plus a lot more. Does not seem like the case here

@Test
public void shouldPersistRecalculatedArticle()
{
  Article articleOne = new Article();
  Article articleTwo = new Article();

  when(mockCalculator.countNumberOfRelatedArticles(articleOne)).thenReturn(1);
  when(mockCalculator.countNumberOfRelatedArticles(articleTwo)).thenReturn(12);
  when(mockDatabase.getArticlesFor("Guardian")).thenReturn(asList(articleOne, articleTwo));

  articleManager.updateRelatedArticlesCounters("Guardian");

  InOrder inOrder = inOrder(mockDatabase, mockCalculator);
  inOrder.verify(mockCalculator).countNumberOfRelatedArticles(isA(Article.class));
  inOrder.verify(mockDatabase, times(2)).save((Article) notNull());
}



@Test
public void shouldPersistRecalculatedArticle()
{
  final Article articleOne = new Article();
  final Article articleTwo = new Article();

  new Expectations() {{
     mockCalculator.countNumberOfRelatedArticles(articleOne); result = 1;
     mockCalculator.countNumberOfRelatedArticles(articleTwo); result = 12;
     mockDatabase.getArticlesFor("Guardian"); result = asList(articleOne, articleTwo);
  }};

  articleManager.updateRelatedArticlesCounters("Guardian");

  new VerificationsInOrder(2) {{
     mockCalculator.countNumberOfRelatedArticles(withInstanceOf(Article.class));
     mockDatabase.save((Article) withNotNull());
  }};
}

A statement like this

inOrder.verify(mockDatabase, times(2)).save((Article) notNull());

in Mockito, does not have an equivalent in JMockIt as you can see from the example above

new NonStrictExpectations(Foo.class, Bar.class, zooObj)
{
    {
        // don't call zooObj.method1() here
        // Otherwise it will get stubbed out
    }
};


new Verifications()
{
    {
        zooObj.method1(); times = N;
    }
};
user855
  • 19,048
  • 38
  • 98
  • 162
  • see this post: http://stackoverflow.com/questions/4105592/comparison-between-mockito-vs-jmockit-why-is-mockito-voted-better-than-jmockit – jeha Oct 08 '11 at 22:24
  • actually it is not equivalent. I dont' think JMockIt can do this – user855 Oct 08 '11 at 23:17

2 Answers2

11

In fact, all mocking APIs mock or stub out every method in the mocked type, by default. I think you confused mock(type) ("full" mocking) with spy(obj) (partial mocking).

JMockit does all that, with a simple API in every case. It's all described, with examples, in the JMockit Tutorial. For proof, you can see the sample test suites (there are many more that have been removed from newer releases of the toolkit, but can still be found in the old zip files), or the many JMockit integration tests (over one thousand currently).

The equivalent to Mockito's spy is "dynamic partial mocking" in JMockit. Simply pass the instances you want to partially mock as arguments to the Expectations constructor. If no expectations are recorded, the real code will be executed when the code under test is exercised. BTW, Mockito has a serious problem here (which JMockit doesn't), because it always executes the real code, even when it's called inside when(...) or verify(...); because of this, people have to use doReturn(...).when(...) to avoid surprises on spied objects.

Regarding verification of invocations, the JMockit Verifications API is considerably more capable than any other. For example:

new VerificationsInOrder() {{
    // preceding invocations, if any
    mockDatabase.save((Article) withNotNull()); times = 2;
    // later invocations, if any
}};
Hulk
  • 6,399
  • 1
  • 30
  • 52
Rogério
  • 16,171
  • 2
  • 50
  • 63
  • 1
    I am getting 404 on the link you provided. Can you please provide updated link? I am trying to learn JMockit. – ersnh Mar 31 '15 at 10:02
6

Mockito's a much older library than JMockIT, so you could expect that it would have many more features. Have a read through the release list if you want to see some of the less well documented functionality. JMockIT authors have produced a matrix of features in which they missed out every single thing that other frameworks do that they don't, and got several wrong (for instance, Mockito can do strict mocks and ordering).

Mockito was also written to enable unit-level BDD. That generally means that if your tests provide a good example of how to use the code, and if your code is lovely and decoupled and well-designed, then you won't need all the shenanigans that JMockIT provides. One of the hardest things to do in Open Source is say "no" to the many requests that don't help in the long run.

Compare the examples on the front pages of Mockito and JMockIT to see the real difference. It's not about what you test, it's about how well your tests document and describe the behavior of the class.

Declaration of Interest: Szczepan and I were on the same project when he wrote the first draft of Mockito, after seeing some of us roll out our own stub classes rather than use the existing mocking frameworks of the time. So I feel like he wrote it all for me, and am thoroughly biased. Thank you Szczepan.

Lunivore
  • 17,277
  • 4
  • 47
  • 92
  • 2
    I sorry, but you got lots of things wrong. If you believe there is something which other tools do that JMockit don't, please show me a test. I already provided proof: see the sample test suite for comparison between JMockit and Mockito, with equivalent test pairs, including *all* the tests found in the Mockito site. (If I missed any, let me know.) Mockito does not support *strict* mocks, ie, those for which missing and unexpected invocations are reported with no additional verification code. Regarding the support for good design, it's the opposite: Mockito prevents it. – Rogério Oct 26 '11 at 18:14
  • Rogerio, Mockito was created because other mocking frameworks were preventing us from properly giving examples of the kind of behavior we were looking for. Did you actually look through Mockito's release list? It's here: http://code.google.com/p/mockito/wiki/ReleaseNotes - most of these are responses to community requests. I don't see the same level of community support in JMockit. Each of these has tests somewhere in the Mockito code. For instance, let me call out the ability to do 'deep stubs' as one thing they do. And if *you* haven't produced good design, it doesn't mean *we* haven't. – Lunivore Oct 26 '11 at 23:07
  • 2
    Lunivore, I spent hundreds of hours studying not only Mockito, but all other mocking tools for Java (and also spent some time on C++, .NET, Ruby and Python mocking tools). I know, for example, that people often run into Mockito's limitations, and ask for support to be added (see issues 12, 101 and 130, or posts in the mailing list such as this one: http://groups.google.com/group/mockito/browse_thread/thread/ef0617e3fda6e8d5). For evidence of community involvement in the JMockit project, have a look at the issues, the "JMockit Users" discussion group, or the change history page. – Rogério Oct 27 '11 at 20:29
  • 2
    Regarding the support for good OO design practices, I created JMockit precisely because existing tools (EasyMock and jMock, by the end of 2005) were lacking, and they still are. With "conventional" mocking APIs, I cannot: a) unit test a class which happens to use a static persistence facade, even though this particular pattern proved very effective to me (and coleagues) in the real world; b) follow the advice of just about any book on API design on the proper use of inheritance. I wrote about such design topics in the "About JMockit" page and in the JMockit Tutorial. – Rogério Oct 27 '11 at 20:38
  • Some of us tend to prefer composition over inheritance, and dependency injection over statics and singletons. Most other BDDers I've met do too. We don't design using mocks. We design by thinking about the scope and responsibilities of our class, and what it should delegate to other classes, then we use mocks to express that. I've never thought, "Oh, I should design in a static persistence facade here, that would be a good idea." Maybe we just have different concepts of good design? – Lunivore Oct 27 '11 at 20:56
  • 2
    I prefer composition too. With JMockit, developers can properly design for extension, making classes or methods `final` to indicate they should not be inherited; this encourages the use of composition, without reducing the ability to write unit tests. I rarely use singletons, but static methods can be used to great effect, as in the case I mentioned, or as an alternative to constructors; JMockit gives the developer freedom to decide whether to use them or not, without being a Nazi about it. My concepts of good design are in line with those of authors such as Fowler, Bloch, McConnel and others. – Rogério Oct 28 '11 at 11:22
  • Lunivore, you said "We design by thinking about the scope and responsibilities of our class, and what it should delegate to other classes, then we use mocks to express that." So what about the case where a class has the responsibility of sending an e-mail? Obviously, we delegate e-mail sending to some other class(es). Suppose a project uses the Apache Commons Email API. With JMockit, I can easily mock the `Email` subclass, while allowing this API to be used in the way it was intended (direct instantiation rather than injection). How else would you do that, and why would it be better? – Rogério Oct 28 '11 at 11:34
  • I'd work out how I want to send an email, then I'd write a nice little interface for that. It should roughly match the bits I need from the Apache Commons Email API. Then I mock it out. After that I write an adapter around the API which directly instantiates it, and should be simple enough to test by inspection & manual testing. It *probably* won't change, after all. I can then change to any other email API if I want because my code is decoupled from this 3rd party library; also it shows other devs which bits of the API which we're actually using and why they're valuable to us. – Lunivore Oct 28 '11 at 12:22
  • You can then also do things like decorate the email adapter using the same interface - for instance, if it's sent an identical email already that day maybe it doesn't want to send another one. Maybe it wants to update some stats on how many emails were sent. You can't do that if you've coupled yourself to the API, and your calling class shouldn't be responsible for it, so you end up rewriting a lot of stuff otherwise. Every time I've coupled to APIs - even reasonable ones like Apache's - it's come back to bite me. – Lunivore Oct 28 '11 at 12:26
  • 1
    [Moving this to chat](http://chat.stackoverflow.com/rooms/4568/discussion-between-lunivore-and-rogerio) - it's now too complicated to carry on here! But happy to do so. – Lunivore Oct 28 '11 at 12:28
  • 1
    Interesting. Anyone recorded this chat so that I can continue reading? – traveh May 06 '15 at 09:14
  • @traveh It didn't go very far. I had to get some work done and took an hour to respond to a comment, which was apparently far too long; he quit on me. Oh, well. – Lunivore May 09 '15 at 16:07
  • Interesting discussion though. I like Mockito but love JMockit. Mockito is good if you start all new and writing new code that you can adapt to work with Mockito. However, if you have to use and test someone else's code (which is a very common case), Mockito will very quickly turn into a nightmare. Just hitting a badly writen static or final class/variable/call, you are done with Mockito. Finito. The weak points of JMockit at the moment is according me is: missing a list of common test solutions in the docs and it uses a little complex syntax, at first try. – Miyagi May 04 '18 at 08:02