2

I am new in mockito framework, and I have a very basic question regarding this, why exactly we are using MockitoJunitRunner class in our junit test class. Also I found the following two points related to this but couldn't get it, can any one explains following two points in detail

The automatic validation of framework usage is actually worth having. It gives you better reporting if you make one of these mistakes.

  • You call verify on a mock, but forget to provide the method call that you are trying to verify.
  • You call one of the when methods (either the static one, or the one after doReturn, doThrow or doAnswer) and pass a mock, but forget to provide the method that you are trying to stub.
SilverNak
  • 3,283
  • 4
  • 28
  • 44
Rohit Sharma
  • 71
  • 2
  • 17
  • @DawoodibnKareem Yes buddy, I copy-pasted a part of your answer because it was not clear to me. Can u explain me specially the 2nd point ? – Rohit Sharma Jun 28 '17 at 06:11
  • I think the right thing for me to do is (1) Expand a bit on that other answer of mine - maybe add some examples or something. Clearly, that answer of mine wasn't good enough - the fact that Rohit, davidxxx and GhostCat all appear to have failed to understand it is a reflection on _me_, not a reflection on them. (2) When I've done that, I can close _this_ question as a duplicate of that one. – Dawood ibn Kareem Jun 28 '17 at 06:35
  • @DawoodibnKareem may be you can explain it here, instead of expanding that answer of yours , if possible. – Rohit Sharma Jun 28 '17 at 06:50
  • OK, I've expanded my answer on the duplicate question. I now show how all the classes of error might look, and indicate why they're reported in the "wrong" place if you don't use automated framework validation. Also, I describe an alternative solution - the new JUnit Rule that the Mockito team added in version 1.10.17. – Dawood ibn Kareem Jun 28 '17 at 10:31
  • 1
    @DawoodibnKareem look my friend I have no intention to point out an error in your answer. I was just asking a simple question referring to few points and It was just a matter of chance that those reference points is from your post. It was totally unintentional. – Rohit Sharma Jun 28 '17 at 11:44

1 Answers1

7

Using MockitoJunitRunner rather than JunitRunner is really optional.

The automatic validation of framework usage is actually worth having. It gives you better reporting if you make one of these mistakes.

The main advantage provided by MockitoJunitRunner is relieving you to explicitly invoke MockitoAnnotations.initMocks(Object) when you use the @Mock way to create your mocks.

But you could also get a few more misuse reports of the Mockito framework by using this runner that may be missing without using it.

The javadoc of the Mockito 1.10.19 version states :

Compatible with JUnit 4.4 and higher, this runner adds following behavior:

  • Initializes mocks annotated with Mock, so that explicit usage of MockitoAnnotations.initMocks(Object) is not necessary. Mocks are initialized before each test method.

  • validates framework usage after each test method. See javadoc for Mockito.validateMockitoUsage().

And the most important part :

Runner is completely optional - there are other ways you can get @Mock working, for example by writing a base class. Explicitly validating framework usage is also optional because it is triggered automatically by Mockito every time you use the framework. See javadoc for Mockito.validateMockitoUsage().

Example of incorrect uses that may be caught out of the box without using the MockitoJunitRunner :

 //Oops, thenReturn() part is missing:
 when(mock.get());

 //Oops, verified method call is inside verify() where it should be on the outside:
 verify(mock.execute());

 //Oops, missing method to verify:
 verify(mock);

But these could not be caught in all cases.

The Mockito.validateMockitoUsage() method that is invoked by the runner and the framework itself gives more explanations about it but in fact it is not complete.

validateMockitoUsage() explicitly validates the framework state to detect invalid use of Mockito. However, this feature is optional because Mockito validates the usage all the time... but there is a gotcha so read on.

Ok. Go on.

Mockito throws exceptions if you misuse it so that you know if your tests are written correctly. The gotcha is that Mockito does the validation next time you use the framework (e.g. next time you verify, stub, call mock etc.). But even though the exception might be thrown in the next test, the exception message contains a navigable stack trace element with location of the defect. Hence you can click and find the place where Mockito was misused.

So, the framework does the validation the next time you use the framework (verify, stub, call mock,etc..).
In fact it is true but not always.

For example this misuse will be caught by the framework :

@Test
public void testBadUseWhen() throws Exception {
   Address mock = Mockito.mock(Address.class);
   Mockito.verify(mock.getAddressLine());
}

org.mockito.exceptions.misusing.NullInsteadOfMockException: Argument passed to verify() should be a mock but is null!

But this misuse will not be caught :

@Test
public void testBadUseWhen() throws Exception {
  Address mock = Mockito.mock(Address.class);
  Mockito.when(mock.getAddressLine());
}

While if I add a new use of Mockito after this uncaught misuse, this time we will get a validation exception :

@Test
public void testBadUseWhen() throws Exception {
    Address mock = Mockito.mock(Address.class); 
    Mockito.when(mock.getAddressLine());
    Mockito.when(mock.getAddressLine());
}

org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here

It will be raised for the second Mockito.when(mock.getAddressLine()); statement invoked but the exception will reference the first Mockito.when(mock.getAddressLine()); statement invoked.

It means that for some bad uses of the framework, you could lose the report information if the last mockito method you are used is incorrectly used.

The javadoc states then :

Sometimes though, you might want to validate the framework usage explicitly. For example, one of the users wanted to put validateMockitoUsage() in his @After method so that he knows immediately when he misused Mockito. Without it, he would have known about it not sooner than next time he used the framework. One more benefit of having validateMockitoUsage() in @After is that jUnit runner and rule will always fail in the test method with defect whereas ordinary 'next-time' validation might fail the next test method. But even though JUnit might report next test as red, don't worry about it and just click at navigable stack trace element in the exception message to instantly locate the place where you misused mockito.

So, to not loosing a potentially misuse for the last one Mockito method invoked during a test class, you can explicitly invoke Mockito.validateMockitoUsage() after each tested method.

So this will do the trick :

@After
public void after() {
    Mockito.validateMockitoUsage();
}

The alternative is using the MockitoJUnitRunner that under the hood invokes Mockito.validateMockitoUsage() after each executed test :

@Override
public void testFinished(Description description) throws Exception {
    super.testFinished(description);
    try {
        Mockito.validateMockitoUsage();
    } catch(Throwable t) {
        notifier.fireTestFailure(new Failure(description, t));
    }
}
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Too quick for me today. And nothing left to write up another answer. Sad. – GhostCat Jun 28 '17 at 06:02
  • I _strongly_ disagree with your contradiction of my answer to that other question, and consider your answer here to be incorrect. You _absolutely will_ get more misuse reports by using this runner, because if you omit the explicit framework validation, the validation occurs on the _next_ unit test **if there is one**. So you lose the message entirely if you're running a single unit test. You get the message reported against the wrong test if you're running a whole series of tests. So there is a _distinct advantage_ to the framework validation. – Dawood ibn Kareem Jun 28 '17 at 06:07
  • Or more correctly, the _next_ call to a Mockito framework method. Which is very often in the next unit test. – Dawood ibn Kareem Jun 28 '17 at 06:13
  • @GhostCat Finally, something to add :) – davidxxx Jun 28 '17 at 06:23
  • @Dawood ibn Kareem You are mainly right but not totally. "So you lose the message entirely if you're running a single unit test." It has no relation with the number of test but the mockito method called. "You get the message reported against the wrong test if you're running a whole series of tests" Yes and no because the stacktrace and the content points to the concerned test. Anyway I updated. – davidxxx Jun 28 '17 at 07:09
  • OK, your edit makes your answer much, much better, and I have upvoted it. I mostly disagree with your previous comment. You will lose the message entirely if you don't make another Mockito framework call. So if you're running more than one test that uses Mockito, you can only lose messages out of the _last_ Mockito-based test that you run. Now suppose you call JUnit through your IDE, and there are loads of unit tests, one of which has invalid use of the Mockito framework. Your IDE shows success and failure of the tests - perhaps as green ticks and red Xs, or something similar. But ... – Dawood ibn Kareem Jun 28 '17 at 09:53
  • ... failing to validate your Mockito usage can lead to your IDE showing a framework error in test A as the success of test A and the failure of test B. The result of this is that the developer tries to fix the wrong test. We really don't want our IDEs to lie to us in this way; hence the importance of validating our framework usage. – Dawood ibn Kareem Jun 28 '17 at 09:56
  • Thanks @davidxxx for such a nice explanation :) – Rohit Sharma Jun 28 '17 at 11:49
  • @Dawood ibn Kareem Thank you for your fair. You were right to challenge me. Improved and detailed answer is always better. "you will lose the message entirely if you don't make another Mockito framework call" I agree and would not mean the contrary. You may have the problem whatever the number of test method that you are executing. It was the point on which I would insist on. – davidxxx Jun 28 '17 at 12:28
  • @Rohit You are very welcome. It is an interesting question which Dawood ibn Kareem had given some good hints on the other post. – davidxxx Jun 28 '17 at 12:30