Core Java

Using Mockito without static imports with Java 8

How to simplify Mockito usage by removing static imports in Java 8 based projects.

Rationale

Mockito API is based on static methods aggregated (mostly) in the (BDD)Mockito class followed by extremely fluent, chained method calls. Mock creation, stubbing and call verification can be initiated with mock/spy/given/then/verify static methods:

@Test
public void shouldVerifyMethodExecution() {
    //given
    TacticalStation tsSpy = BDDMockito.spy(TacticalStation.class);
    BDDMockito.willDoNothing().given(tsSpy).fireTorpedo(2);
    //when
    tsSpy.fireTorpedo(2);
    tsSpy.fireTorpedo(2);
    //then
    BDDMockito.then(tsSpy).should(BDDMockito.times(2)).fireTorpedo(2);
}

Quite verbose, but starting with Java 5 one can use static imports to simplify the code, but at the cost of additional static imports:

import static org.mockito.BDDMockito.then;
import static org.mockito.BDDMockito.willDoNothing;
import static org.mockito.BDDMockito.spy;
import static org.mockito.BDDMockito.times;
(...)

@Test
public void shouldVerifyMethodExecution() {
    //given
    TacticalStation tsSpy = spy(TacticalStation.class);
    willDoNothing().given(tsSpy).fireTorpedo(2);
    //when
    tsSpy.fireTorpedo(2);
    tsSpy.fireTorpedo(2);
    //then
    then(tsSpy).should(times(2)).fireTorpedo(2);
}

Imports can be hidden in IDE and usually do not disturb much. Nevertheless to be able to write just a method name (e.g. mock(TacticalStation.class)) without a class is it required to press ALT-ENTER (in IntelliJ IDEA) to add each static import on the first usage of a given method in a test class. The situation is even worse in Eclipse where it is required to earlier add BDDMockito to “Favorites” in “Content Assist” to make it suggested by IDE. Eclipse guys could say “you have to do it just once”, but as I experienced during my testing/TDD trainings it makes a Mockito learning (usage) curve a little bit steeper.

Of course there are some tricks like using star imports by default for Mockito classes to reduce number of required key strokes, but if you use Java 8 in your project (hopefully a majority of you) there is a simpler way to cope with it.

Static imports free approach

Mockito-Java8 2.0.0 (and its counterpart for Mockito 1.10.x – version 1.0.0) introduces a set of interfaces which provide all methods from Mockito API. By “implement” them in a test class all those methods become automatically directly accessible in written tests:

//no static imports needed!

public class SpaceShipTest implements WithBDDMockito {

    @Test
    public void shouldVerifyMethodExecution() {
        //given
        TacticalStation tsSpy = spy(TacticalStation.class);
        willDoNothing().given(tsSpy).fireTorpedo(2);
        //when
        tsSpy.fireTorpedo(2);
        tsSpy.fireTorpedo(2);
        //then
        then(tsSpy).should(times(2)).fireTorpedo(2);
    }
}

The code looks exactly like in the previous snippet, but there is not need to do any static import (besides a normal import of WithBDDMockito itself).

Under the hood the WithBDDMockito interface implementation is dead simple. All methods are default methods which just delegate to proper static method in BDDMockito class.

default <T> BDDMockito.BDDMyOngoingStubbing<T> given(T methodCall) {
    return BDDMockito.given(methodCall);
}

Flavors of Mockito

Mockito methods are provided by 3 base interfaces, being an entry points for given set of methods:

  • WithBDDMockito – stubbing/mocking API in BDD style (provides also classic API).
  • WithMockito – classic stubbing/mocking API
  • WithAdditionalMatchers – additional Mokcito matchers (basic account are included in With(BDD)Mockito)

Summary

Java 8 has opened the new opportunities how (test) code can be written in more compact and readable way. Static imports free Mockito code can simplify writing tests a little bit, but there is more feature already available in Mockito-Java8 and even more to be included in Mockito 3.0 (those for which Mokcito internals have to be modified in a non backward compatible way). Too take more ideas how code/projects can be refactored to benefit from Java 8 you can see my short presentation “Java 8 brings power to testing!” (slides and video).

Mockito-Java8 2.0.0-beta (for Mockito >=2.0.22-beta) and 1.0.0-beta (for Mockito 1.10.x and earlier betas of Mockito 2) is available through Maven Central. The versions should be pretty stable, but I would like to get wider feedback about this new feature, so it is labeled as beta. More details can be found on the project webpage.

Acknowledge. The idea was originally proposed by David Gageot (the guy behind Infinitest) in one of his blog posts.

Reference: Using Mockito without static imports with Java 8 from our JCG partner Marcin Zajaczkowski at the Solid Soft blog.

Marcin Zajaczkowski

Marcin is an experienced architect who specializes in creating high quality software. Being under the impression of the Agile methodologies and the Software Craftsmanship movement, he believes in the value of good, testable and maintainable code. He aims to forge good software that makes the client delighted and the team proud of how the code itself looks.In his teaching, as a conference speaker, college lecturer, IT coach and trainer, he shows how to guide software development effectively using tests (with TDD, pair programming, Clean Code, design patterns, etc.) and maintaining a quality-oriented development environment (with CI, Sonar, automatic deployment, etc.).He is also a FOSS projects author and contributor, a Linux enthusiast.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
pulse
pulse
9 years ago

Nice trick for clean code…

Back to top button