At last! Thank for your patience! Thank you for mocking and writing good tests with us. We are proud of this release for several reasons:

  • Mockito 2 marks an achievement as a non-funded open source software (OSS) project.
    As you know OSS contribution is always a demanding task, and private life matters like health, family, etc requires balance when it comes to spend time on such activities.
    In addition, having a common agenda across team members is a challenge in itself. Contributors outside the team had a huge part in making mockito 2 happen. Thank you so much!
  • Mockito wants to embody what the best mocks are. That’s we spent quite some time meddling with other bytecode generating projects [1][2][3] and trying to write one ourselves. Without solid enough success we set aside these activities, until we were contacted by Rafael Winterhalter who proposed his tool ByteBuddy. This library is the Swiss army knife of Java Bytecode. Using the capabilities of this tool we leveraged numerous issues that were hard to bypass, and more especially we are now incubating another engine that can mock final class and/or final methods.
  • Mockito will try its best to educate about the test quality regarding its usage of mocks and stubs.
  • The project proved that continuous delivery is a nice feature for an OSS project, we’ll continue to explore on the matter with a trial and error.
  • It materialised breaking changes due to some API shortcomings we discovered along the life of 1.x. But we are going to die trying to keep back-compatibility as a top requirement.
  • It is just in time before OpenJdk6 end-of-life

Code-wise, what should you be interested in?

BDD

Mockito brought BDD aliases in the 1.x series. With Mockito 2.1.0 the improved APIs covers now stub verification with the BDD semantics. In this example 1.x users would have to use `Mockito.verify`, now they can use BDD words:


@Test public void should_do_it_the_BDD_way() {
  // Given
  BDDMockito.given(mock.doThis()).willReturn(...);
  BDDMockito.given(mock.doThat()).willReturn(...);

  // When
  subject.performAction();

  // Then
  BDDMockito.then(mock).should(inOrder).doSomething();
  BDDMockito.then(mock).shouldHaveZeroInteractions();
  BDDMockito.then(person).shouldHaveNoMoreInteractions();
}

Matchers

Matchers are mostly the same. However there are 3 notable changes:

  • Matchers are now located in ArgumentMatchers, this will avoid a name clash in the IDE when crafting tests using both Hamcrest matchers and MockitoMatchers. However the change is made in such a way that the user should not be forced to change the imports.
  • Mockito no longer requires a specific version of Hamcrest. However instead of using Matchers.argThat(), Hamcrest users will have to change the import to MockitoHamcrest.argThat()
  • Over the years with different JDK capabilities, the any family matcher began to have non-intuitive behaviour. Did you know that using any(A.class) in 1.x did not check the argument type to be A ? After a lot of discussion and a welcome feedback from the community we chose to make any family intuitive given their signature, in Mockito 2:
    • with a stub like given(mock.performWith(any())).willReturn(0), any() will matches absolutely anything including null
    • with a stub like given(mock.performWith(any(A.class))).willReturn(0), <T> any(Class<T>) will match non null object of type A
    • with a stub like given(mock.performWith(anyString())).willReturn(0), String anyString() will match non null object of type String
    • with a stub like given(mock.performWith(anyListOf(A.class))).willReturn(0), List<T> anyListOf(Class<T>) will match non null List ; at this time this matcher is shallow i.e. the matcher won’t check the type of the collection items

Quality

Long projects have so many changes over the years that developers regularly have to clean up the code. IDEs help hugely in tracking unused code, deprecated, etc. But for unused stubs there isn’t anything. We decided it should be a feature of Mockito to track those in order to improve the quality of the test codebase. Now with tests that looks like:

@Rule public MockitoRule mRule = MockitoJUnit.rule();
@Mock private C c;
@Test public void test_that_dont_need_a_stub() {
  given(c.perform()).willReturn(0);
  // nothing trigger this stubs
}

The test will pass but you should see on the standard output :

[MockitoHint] UnusedStubTest.test_that_dont_need_a_stub (see javadoc for MockitoHint):
[MockitoHint] 1. Unused -> at mockito.bug.snippet.UnusedStubTest.test_that_dont_need_a_stub(UnusedStubTest.java:27)

This behaviour is the default but it can be reverted with MockitoJUnit.rule().silent().

Not that JUnit rules will become the preferred way to create and inject mocks. The rule allows us to extend how a test can be configured in much more convenient way than a runner. At some point we will extend the rule to offer more configuration.

Collect all stub verifications together

@Rule public VerificationCollector collector = MockitoJUnit.collector();
@Mock A collaborator;
@InjectMocks Subject subject;
@Test public void should_behave() {
  subject.should_have_invoked_2_methods_on_A();

  verify(collaborator).method_1();
  verify(collaborator).method_2();
}

Should fail and describe the error as :

org.mockito.exceptions.base.MockitoAssertionError: There were multiple verification failures:
1. Wanted but not invoked:
collaborator.method_1();
-> at my_package.SubjectTest.should_behave(SubjectTest.java:45)
Actually, there were zero interactions with this mock.

2. Wanted but not invoked:
collaborator.method_2();
-> at my_package.SubjectTest.should_behave(SubjectTest.java:46)
Actually, there were zero interactions with this mock.

Java 8

Mockito 2.1.0 sits across Java versions, we dropped support for the Java 5 runtime and but we still produce compatible code for the Java 6 runtime. However with improvements in the compiler of Java 7 and especially Java 8, we found that Mockito 2 should focus on Java 8 rather than older runtimes.

  • If a method return type is Optional or Stream Mockito will use respectively Optional.empty() or Stream.empty() as default values instead of null.
  • We tweaked signature for the Java 8 platform, the <T> Set<T> anySet() matcher for example now returns a parametric return type. With this little change the tactical alias method <T> Set<T> anySetOf(Class<T>) is not needed anymore with a Java 8 runtime and will be probably be removed in Mockito 3.
    given(mock.performWith(anyListOf(A.class))).willReturn(0);
    given(mock.performWith(anyList())).willReturn(0)
    
  • It is possible to stub default methods of interfaces:
    interface Contract {
      default Optional<Integer> contract() { return Optional.of(73); }
    }
    

    The stub will work in the following way

    // not stubbed, the method will return default value
    assertThat(c.contract()).isEqualTo(Optional.empty());
    
    // stubbed to return something else
    given(c.contract()).willReturn(Optional.of(2));
    assertThat(c.contract()).hasValue(2);
    
    // stubbed to execute real code
    given(c.contract()).willCallRealMethod();
    assertThat(c.contract()).hasValue(73);
    

Full blown support of Java 8 will be coming with Mockito 3. The reason behind that is that some types are not available in previous JDKs and as such could not appear in the class definition. For example a matcher with the signature <T> Stream<T> anyStream() would fail to load on JDK 7. Mockito 2 should help projects in transit between two JDK versions.

Mocks of unmockable

Mocking final classes or final method feature is now possible, only with Mockito. The feature is not yet promoted as the default mode or even as an API; the team has to gain experience and user feedback. The only thing to do is make a file /mockito-extensions/org.mockito.plugins.MockMaker with the single line :

mock-maker-inline

Note that while mocking final classes is now possible, everyone must still question the act of mocking a type not owned (as in code ownership). For example

  • You don’t want to mock final class Pattern, its behaviour changes between JDK versions. Your tests could be green but production code is wrong.
  • You don’t want to mock non-final class HashMap, its behaviour can change between JDK versions. Again, your tests could be green but production code is wrong.

A word about the implementation

Mocks have come a long way. Many contributors and frameworks helped us to better understand how they could be implemented; from manual implementation, to JMock, then to EasyMock (that introduced a way to mock classes not only interfaces), then Mockito, which is a fork of EasyMock that now introduces mocks of final classes or final methods.

For a long time Mockito was limited to mock non-final classes. And the reason is that Mockito generated its own mock classes as subclasses of type to mock, this requires the type to be not final. Final methods could not be overloaded in the subclasses and as such generated frustration in cases when tests required these to be mocked.
In order to bypass this limitation, frameworks like Powermock used clever tricks with classloaders to modify the necessary classes to make them non final, and then run the test in this specific classloader.

Mockito’s way to mock final classes is to use an agent that modifies the type to mock. Instead of modifying the final modifier, the code will either redirect to the concrete code or to the defined stub.

Mocking final classes is hard topic, all approaches comes with their own drawbacks. Class transformation is more invasive and cannot work with some methods like native methods, but this approach is much easier to use. At some point we will offer a programatic way to control how mocks are created.

Mockito 2.1.0

About The Author
- independant contractor in java developement — Mockito commiter — Devoxx France Java Track Lead  — Also Event Sourcing / CQRS enthusiast

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>