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 APIWithAdditionalMatchers
– 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. |
Nice trick for clean code…